highlight_spec.lua (60405B)
1 local t = require('test.testutil') 2 local n = require('test.functional.testnvim')() 3 local Screen = require('test.functional.ui.screen') 4 5 local clear = n.clear 6 local insert = n.insert 7 local exec_lua = n.exec_lua 8 local eval = n.eval 9 local feed = n.feed 10 local command = n.command 11 local api = n.api 12 local fn = n.fn 13 local eq = t.eq 14 15 local hl_query_c = [[ 16 ; query 17 (ERROR) @error 18 19 "if" @keyword 20 "else" @keyword 21 "for" @keyword 22 "return" @keyword 23 24 "const" @type 25 "static" @type 26 "struct" @type 27 "enum" @type 28 "extern" @type 29 30 ; nonexistent specializer for string should fallback to string 31 (string_literal) @string.nonexistent_specializer 32 33 (number_literal) @number 34 (char_literal) @string 35 36 (type_identifier) @type 37 ((type_identifier) @constant.builtin (#eq? @constant.builtin "LuaRef")) 38 39 (primitive_type) @type 40 (sized_type_specifier) @type 41 42 ; Use lua regexes 43 ((identifier) @function (#contains? @function "lua_")) 44 ((identifier) @Constant (#lua-match? @Constant "^[A-Z_]+$")) 45 ((identifier) @Normal (#vim-match? @Normal "^lstate$")) 46 47 ((binary_expression left: (identifier) @warning.left right: (identifier) @warning.right) (#eq? @warning.left @warning.right)) 48 49 (comment) @comment 50 ]] 51 52 local hl_text_c = [[ 53 /// Schedule Lua callback on main loop's event queue 54 static int nlua_schedule(lua_State *const lstate) 55 { 56 if (lua_type(lstate, 1) != LUA_TFUNCTION 57 || lstate != lstate) { 58 lua_pushliteral(lstate, "vim.schedule: expected function"); 59 return lua_error(lstate); 60 } 61 62 LuaRef cb = nlua_ref(lstate, 1); 63 64 multiqueue_put(main_loop.events, nlua_schedule_event, 65 1, (void *)(ptrdiff_t)cb); 66 return 0; 67 }]] 68 69 local hl_grid_legacy_c = [[ 70 {18:^/// Schedule Lua callback on main loop's event queue} | 71 {6:static} {6:int} nlua_schedule(lua_State *{6:const} lstate) | 72 { | 73 {15:if} (lua_type(lstate, {26:1}) != LUA_TFUNCTION | 74 || lstate != lstate) { | 75 lua_pushliteral(lstate, {26:"vim.schedule: expected function"}); | 76 {15:return} lua_error(lstate); | 77 } | 78 | 79 LuaRef cb = nlua_ref(lstate, {26:1}); | 80 | 81 multiqueue_put(main_loop.events, nlua_schedule_event, | 82 {26:1}, ({6:void} *)({6:ptrdiff_t})cb); | 83 {15:return} {26:0}; | 84 } | 85 {1:~ }|*2 86 14 more lines | 87 ]] 88 89 local hl_grid_ts_c = [[ 90 {18:^/// Schedule Lua callback on main loop's event queue} | 91 {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) | 92 { | 93 {15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} | 94 || {19:lstate} != {19:lstate}) { | 95 {25:lua_pushliteral}(lstate, {26:"vim.schedule: expected function"}); | 96 {15:return} {25:lua_error}(lstate); | 97 } | 98 | 99 {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); | 100 | 101 multiqueue_put(main_loop.events, {25:nlua_schedule_event}, | 102 {26:1}, ({6:void} *)({6:ptrdiff_t})cb); | 103 {15:return} {26:0}; | 104 } | 105 {1:~ }|*2 106 {MATCH:1?4? m?o?r?e? l?i?n?e?s?.*}| 107 ]] 108 109 local test_text_c = [[ 110 void ui_refresh(void) 111 { 112 int width = INT_MAX, height = INT_MAX; 113 bool ext_widgets[kUIExtCount]; 114 for (UIExtension i = 0; (int)i < kUIExtCount; i++) { 115 ext_widgets[i] = true; 116 } 117 118 bool inclusive = ui_override(); 119 for (size_t i = 0; i < ui_count; i++) { 120 UI *ui = uis[i]; 121 width = MIN(ui->width, width); 122 height = MIN(ui->height, height); 123 foo = BAR(ui->bazaar, bazaar); 124 for (UIExtension j = 0; (int)j < kUIExtCount; j++) { 125 ext_widgets[j] &= (ui->ui_ext[j] || inclusive); 126 } 127 } 128 }]] 129 130 local injection_text_c = [[ 131 int x = INT_MAX; 132 #define READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) 133 #define foo void main() { \ 134 return 42; \ 135 } 136 ]] 137 138 local injection_grid_c = [[ 139 int x = INT_MAX; | 140 #define READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) | 141 #define foo void main() { \ | 142 return 42; \ | 143 } | 144 ^ | 145 {1:~ }|*11 146 | 147 ]] 148 149 local injection_grid_expected_c = [[ 150 {6:int} x = {26:INT_MAX}; | 151 #define {26:READ_STRING}(x, y) ({6:char} *)read_string((x), ({6:size_t})(y)) | 152 #define foo {6:void} main() { \ | 153 {15:return} {26:42}; \ | 154 } | 155 ^ | 156 {1:~ }|*11 157 | 158 ]] 159 160 describe('treesitter highlighting (C)', function() 161 local screen --- @type test.functional.ui.screen 162 163 before_each(function() 164 clear() 165 screen = Screen.new(65, 18) 166 command [[ hi link @error ErrorMsg ]] 167 command [[ hi link @warning WarningMsg ]] 168 end) 169 170 it('starting and stopping treesitter highlight works', function() 171 command('setfiletype c | syntax on') 172 fn.setreg('r', hl_text_c) 173 feed('i<C-R><C-O>r<Esc>gg') 174 -- legacy syntax highlighting is used by default 175 screen:expect(hl_grid_legacy_c) 176 177 exec_lua(function() 178 vim.treesitter.query.set('c', 'highlights', hl_query_c) 179 vim.treesitter.start() 180 end) 181 -- treesitter highlighting is used 182 screen:expect(hl_grid_ts_c) 183 184 exec_lua(function() 185 vim.treesitter.stop() 186 end) 187 -- legacy syntax highlighting is used 188 screen:expect(hl_grid_legacy_c) 189 190 exec_lua(function() 191 vim.treesitter.start() 192 end) 193 -- treesitter highlighting is used 194 screen:expect(hl_grid_ts_c) 195 196 exec_lua(function() 197 vim.treesitter.stop() 198 end) 199 -- legacy syntax highlighting is used 200 screen:expect(hl_grid_legacy_c) 201 202 exec_lua(function() 203 vim.cmd 'new | wincmd p' 204 vim.treesitter.start() 205 vim.cmd 'bdelete!' 206 end) 207 -- Does not change &syntax of the other, unrelated buffer. 208 eq('', eval('&syntax')) 209 end) 210 211 it('is updated with edits', function() 212 insert(hl_text_c) 213 feed('gg') 214 screen:expect { 215 grid = [[ 216 ^/// Schedule Lua callback on main loop's event queue | 217 static int nlua_schedule(lua_State *const lstate) | 218 { | 219 if (lua_type(lstate, 1) != LUA_TFUNCTION | 220 || lstate != lstate) { | 221 lua_pushliteral(lstate, "vim.schedule: expected function"); | 222 return lua_error(lstate); | 223 } | 224 | 225 LuaRef cb = nlua_ref(lstate, 1); | 226 | 227 multiqueue_put(main_loop.events, nlua_schedule_event, | 228 1, (void *)(ptrdiff_t)cb); | 229 return 0; | 230 } | 231 {1:~ }|*2 232 | 233 ]], 234 } 235 236 exec_lua(function() 237 local parser = vim.treesitter.get_parser(0, 'c') 238 local highlighter = vim.treesitter.highlighter 239 highlighter.new(parser, { queries = { c = hl_query_c } }) 240 end) 241 screen:expect(hl_grid_ts_c) 242 243 feed('5Goc<esc>dd') 244 245 screen:expect({ 246 grid = [[ 247 {18:/// Schedule Lua callback on main loop's event queue} | 248 {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) | 249 { | 250 {15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} | 251 || {19:lstate} != {19:lstate}) { | 252 {25:^lua_pushliteral}(lstate, {26:"vim.schedule: expected function"}); | 253 {15:return} {25:lua_error}(lstate); | 254 } | 255 | 256 {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); | 257 | 258 multiqueue_put(main_loop.events, {25:nlua_schedule_event}, | 259 {26:1}, ({6:void} *)({6:ptrdiff_t})cb); | 260 {15:return} {26:0}; | 261 } | 262 {1:~ }|*2 263 | 264 ]], 265 }) 266 267 feed('7Go*/<esc>') 268 screen:expect({ 269 grid = [[ 270 {18:/// Schedule Lua callback on main loop's event queue} | 271 {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) | 272 { | 273 {15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} | 274 || {19:lstate} != {19:lstate}) { | 275 {25:lua_pushliteral}(lstate, {26:"vim.schedule: expected function"}); | 276 {15:return} {25:lua_error}(lstate); | 277 {9:*^/} | 278 } | 279 | 280 {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); | 281 | 282 multiqueue_put(main_loop.events, {25:nlua_schedule_event}, | 283 {26:1}, ({6:void} *)({6:ptrdiff_t})cb); | 284 {15:return} {26:0}; | 285 } | 286 {1:~ }| 287 | 288 ]], 289 }) 290 291 feed('3Go/*<esc>') 292 screen:expect({ 293 grid = [[ 294 {18:/// Schedule Lua callback on main loop's event queue} | 295 {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) | 296 { | 297 {18:/^*} | 298 {18: if (lua_type(lstate, 1) != LUA_TFUNCTION} | 299 {18: || lstate != lstate) {} | 300 {18: lua_pushliteral(lstate, "vim.schedule: expected function");} | 301 {18: return lua_error(lstate);} | 302 {18:*/} | 303 } | 304 | 305 {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); | 306 | 307 multiqueue_put(main_loop.events, {25:nlua_schedule_event}, | 308 {26:1}, ({6:void} *)({6:ptrdiff_t})cb); | 309 {15:return} {26:0}; | 310 {9:}} | 311 | 312 ]], 313 }) 314 315 feed('gg$') 316 feed('~') 317 screen:expect({ 318 grid = [[ 319 {18:/// Schedule Lua callback on main loop's event queu^E} | 320 {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) | 321 { | 322 {18:/*} | 323 {18: if (lua_type(lstate, 1) != LUA_TFUNCTION} | 324 {18: || lstate != lstate) {} | 325 {18: lua_pushliteral(lstate, "vim.schedule: expected function");} | 326 {18: return lua_error(lstate);} | 327 {18:*/} | 328 } | 329 | 330 {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); | 331 | 332 multiqueue_put(main_loop.events, {25:nlua_schedule_event}, | 333 {26:1}, ({6:void} *)({6:ptrdiff_t})cb); | 334 {15:return} {26:0}; | 335 {9:}} | 336 | 337 ]], 338 }) 339 340 feed('re') 341 screen:expect({ 342 grid = [[ 343 {18:/// Schedule Lua callback on main loop's event queu^e} | 344 {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) | 345 { | 346 {18:/*} | 347 {18: if (lua_type(lstate, 1) != LUA_TFUNCTION} | 348 {18: || lstate != lstate) {} | 349 {18: lua_pushliteral(lstate, "vim.schedule: expected function");} | 350 {18: return lua_error(lstate);} | 351 {18:*/} | 352 } | 353 | 354 {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); | 355 | 356 multiqueue_put(main_loop.events, {25:nlua_schedule_event}, | 357 {26:1}, ({6:void} *)({6:ptrdiff_t})cb); | 358 {15:return} {26:0}; | 359 {9:}} | 360 | 361 ]], 362 }) 363 end) 364 365 it('is updated with :sort', function() 366 insert(test_text_c) 367 exec_lua(function() 368 local parser = vim.treesitter.get_parser(0, 'c') 369 vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } }) 370 end) 371 screen:expect({ 372 grid = [[ 373 {6:int} width = {26:INT_MAX}, height = {26:INT_MAX}; | 374 {6:bool} ext_widgets[kUIExtCount]; | 375 {15:for} ({6:UIExtension} i = {26:0}; ({6:int})i < kUIExtCount; i++) { | 376 ext_widgets[i] = true; | 377 } | 378 | 379 {6:bool} inclusive = ui_override(); | 380 {15:for} ({6:size_t} i = {26:0}; i < ui_count; i++) { | 381 {6:UI} *ui = uis[i]; | 382 width = {26:MIN}(ui->width, width); | 383 height = {26:MIN}(ui->height, height); | 384 foo = {26:BAR}(ui->bazaar, bazaar); | 385 {15:for} ({6:UIExtension} j = {26:0}; ({6:int})j < kUIExtCount; j++) { | 386 ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | 387 } | 388 } | 389 ^} | 390 | 391 ]], 392 }) 393 394 feed ':sort<cr>' 395 screen:expect({ 396 grid = [[ 397 ^ | 398 ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | 399 {6:UI} *ui = uis[i]; | 400 ext_widgets[i] = true; | 401 foo = {26:BAR}(ui->bazaar, bazaar); | 402 {15:for} ({6:UIExtension} j = {26:0}; ({6:int})j < kUIExtCount; j++) { | 403 height = {26:MIN}(ui->height, height); | 404 width = {26:MIN}(ui->width, width); | 405 } | 406 {6:bool} ext_widgets[kUIExtCount]; | 407 {6:bool} inclusive = ui_override(); | 408 {15:for} ({6:UIExtension} i = {26:0}; ({6:int})i < kUIExtCount; i++) { | 409 {15:for} ({6:size_t} i = {26:0}; i < ui_count; i++) { | 410 {6:int} width = {26:INT_MAX}, height = {26:INT_MAX}; | 411 } |*2 412 {6:void} ui_refresh({6:void}) | 413 :sort | 414 ]], 415 }) 416 417 feed 'u:<esc>' 418 419 screen:expect({ 420 grid = [[ 421 {6:int} width = {26:INT_MAX}, height = {26:INT_MAX}; | 422 {6:bool} ext_widgets[kUIExtCount]; | 423 {15:for} ({6:UIExtension} i = {26:0}; ({6:int})i < kUIExtCount; i++) { | 424 ext_widgets[i] = true; | 425 } | 426 | 427 {6:bool} inclusive = ui_override(); | 428 {15:for} ({6:size_t} i = {26:0}; i < ui_count; i++) { | 429 {6:UI} *ui = uis[i]; | 430 width = {26:MIN}(ui->width, width); | 431 height = {26:MIN}(ui->height, height); | 432 foo = {26:BAR}(ui->bazaar, bazaar); | 433 {15:for} ({6:UIExtension} j = {26:0}; ({6:int})j < kUIExtCount; j++) { | 434 ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | 435 } | 436 } | 437 ^} | 438 | 439 ]], 440 }) 441 end) 442 443 it('supports with custom parser', function() 444 insert(test_text_c) 445 446 screen:expect { 447 grid = [[ 448 int width = INT_MAX, height = INT_MAX; | 449 bool ext_widgets[kUIExtCount]; | 450 for (UIExtension i = 0; (int)i < kUIExtCount; i++) { | 451 ext_widgets[i] = true; | 452 } | 453 | 454 bool inclusive = ui_override(); | 455 for (size_t i = 0; i < ui_count; i++) { | 456 UI *ui = uis[i]; | 457 width = MIN(ui->width, width); | 458 height = MIN(ui->height, height); | 459 foo = BAR(ui->bazaar, bazaar); | 460 for (UIExtension j = 0; (int)j < kUIExtCount; j++) { | 461 ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | 462 } | 463 } | 464 ^} | 465 | 466 ]], 467 } 468 469 exec_lua(function() 470 local parser = vim.treesitter.get_parser(0, 'c') 471 local query = vim.treesitter.query.parse('c', '(declaration) @decl') 472 473 local nodes = {} 474 for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do 475 table.insert(nodes, node) 476 end 477 478 parser:set_included_regions({ nodes }) 479 480 vim.treesitter.highlighter.new(parser, { queries = { c = '(identifier) @type' } }) 481 end) 482 483 screen:expect({ 484 grid = [[ 485 int {6:width} = {6:INT_MAX}, {6:height} = {6:INT_MAX}; | 486 bool {6:ext_widgets}[{6:kUIExtCount}]; | 487 for (UIExtension {6:i} = 0; (int)i < kUIExtCount; i++) { | 488 ext_widgets[i] = true; | 489 } | 490 | 491 bool {6:inclusive} = {6:ui_override}(); | 492 for (size_t {6:i} = 0; i < ui_count; i++) { | 493 UI *{6:ui} = {6:uis}[{6:i}]; | 494 width = MIN(ui->width, width); | 495 height = MIN(ui->height, height); | 496 foo = BAR(ui->bazaar, bazaar); | 497 for (UIExtension {6:j} = 0; (int)j < kUIExtCount; j++) { | 498 ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | 499 } | 500 } | 501 ^} | 502 | 503 ]], 504 }) 505 end) 506 507 it('supports injected languages', function() 508 insert(injection_text_c) 509 510 screen:expect { grid = injection_grid_c } 511 512 exec_lua(function() 513 local parser = vim.treesitter.get_parser(0, 'c', { 514 injections = { 515 c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))', 516 }, 517 }) 518 local highlighter = vim.treesitter.highlighter 519 highlighter.new(parser, { queries = { c = hl_query_c } }) 520 end) 521 522 screen:expect { grid = injection_grid_expected_c } 523 end) 524 525 it('supports combined injections #31777', function() 526 insert([=[ 527 -- print([[ 528 -- some 529 -- random 530 -- text 531 -- here]]) 532 ]=]) 533 534 exec_lua(function() 535 local parser = vim.treesitter.get_parser(0, 'lua', { 536 injections = { 537 lua = [[ 538 ; query 539 ((comment_content) @injection.content 540 (#set! injection.self) 541 (#set! injection.combined)) 542 ]], 543 }, 544 }) 545 local highlighter = vim.treesitter.highlighter 546 highlighter.new(parser, { 547 queries = { 548 lua = [[ 549 ; query 550 (string) @string 551 (comment) @comment 552 (function_call (identifier) @function.call) 553 [ "(" ")" ] @punctuation.bracket 554 ]], 555 }, 556 }) 557 end) 558 559 screen:expect([=[ 560 {18:-- }{25:print}{16:(}{26:[[} | 561 {18:--}{26: some} | 562 {18:--}{26: random} | 563 {18:--}{26: text} | 564 {18:--}{26: here]]}{16:)} | 565 ^ | 566 {1:~ }|*11 567 | 568 ]=]) 569 end) 570 571 it('supports complicated combined injections', function() 572 insert([[ 573 -- # Markdown here 574 -- 575 -- ```c 576 -- int main() { 577 -- printf("Hello, world!"); 578 -- } 579 -- ``` 580 ]]) 581 582 exec_lua(function() 583 local parser = vim.treesitter.get_parser(0, 'lua', { 584 injections = { 585 lua = [[ 586 ; query 587 ((comment) @injection.content 588 (#offset! @injection.content 0 3 0 1) 589 (#lua-match? @injection.content "[-][-] ") 590 (#set! injection.combined) 591 (#set! injection.include-children) 592 (#set! injection.language "markdown")) 593 ]], 594 }, 595 }) 596 local highlighter = vim.treesitter.highlighter 597 highlighter.new(parser, { 598 queries = { 599 lua = [[ 600 ; query 601 (string) @string 602 (comment) @comment 603 (function_call (identifier) @function.call) 604 [ "(" ")" ] @punctuation.bracket 605 ]], 606 }, 607 }) 608 end) 609 610 screen:add_extra_attr_ids({ 611 [131] = { foreground = Screen.colors.Fuchsia, bold = true }, 612 }) 613 614 screen:expect([[ 615 {18:-- }{131:# Markdown here} | 616 {18:--} | 617 {18:-- ```}{15:c} | 618 {18:-- }{16:int}{18: }{25:main}{16:()}{18: }{16:{} | 619 {18:-- }{25:printf}{16:(}{26:"Hello, world!"}{16:);} | 620 {18:-- }{16:}} | 621 {18:-- ```} | 622 ^ | 623 {1:~ }|*9 624 | 625 ]]) 626 end) 627 628 it("supports injecting by ft name in metadata['injection.language']", function() 629 insert(injection_text_c) 630 631 screen:expect { grid = injection_grid_c } 632 633 exec_lua(function() 634 vim.treesitter.language.register('c', 'foo') 635 local parser = vim.treesitter.get_parser(0, 'c', { 636 injections = { 637 c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "foo")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "foo"))', 638 }, 639 }) 640 local highlighter = vim.treesitter.highlighter 641 highlighter.new(parser, { queries = { c = hl_query_c } }) 642 end) 643 644 screen:expect { grid = injection_grid_expected_c } 645 end) 646 647 it('supports overriding queries, like ', function() 648 insert([[ 649 int x = INT_MAX; 650 #define READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) 651 #define foo void main() { \ 652 return 42; \ 653 } 654 ]]) 655 656 exec_lua(function() 657 local injection_query = 658 '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' 659 vim.treesitter.query.set('c', 'highlights', hl_query_c) 660 vim.treesitter.query.set('c', 'injections', injection_query) 661 662 vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c')) 663 end) 664 665 screen:expect({ 666 grid = [[ 667 {6:int} x = {26:INT_MAX}; | 668 #define {26:READ_STRING}(x, y) ({6:char} *)read_string((x), ({6:size_t})(y)) | 669 #define foo {6:void} main() { \ | 670 {15:return} {26:42}; \ | 671 } | 672 ^ | 673 {1:~ }|*11 674 | 675 ]], 676 }) 677 end) 678 679 it('supports highlighting with custom highlight groups', function() 680 insert(hl_text_c) 681 feed('gg') 682 683 exec_lua(function() 684 local parser = vim.treesitter.get_parser(0, 'c') 685 vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } }) 686 end) 687 688 screen:expect(hl_grid_ts_c) 689 690 -- This will change ONLY the literal strings to look like comments 691 -- The only literal string is the "vim.schedule: expected function" in this test. 692 exec_lua [[vim.cmd("highlight link @string.nonexistent_specializer comment")]] 693 screen:expect({ 694 grid = [[ 695 {18:^/// Schedule Lua callback on main loop's event queue} | 696 {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) | 697 { | 698 {15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} | 699 || {19:lstate} != {19:lstate}) { | 700 {25:lua_pushliteral}(lstate, {18:"vim.schedule: expected function"}); | 701 {15:return} {25:lua_error}(lstate); | 702 } | 703 | 704 {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); | 705 | 706 multiqueue_put(main_loop.events, {25:nlua_schedule_event}, | 707 {26:1}, ({6:void} *)({6:ptrdiff_t})cb); | 708 {15:return} {26:0}; | 709 } | 710 {1:~ }|*2 711 | 712 ]], 713 }) 714 screen:expect { unchanged = true } 715 end) 716 717 it('supports highlighting with priority', function() 718 insert([[ 719 int x = INT_MAX; 720 #define READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) 721 #define foo void main() { \ 722 return 42; \ 723 } 724 ]]) 725 726 exec_lua(function() 727 local parser = vim.treesitter.get_parser(0, 'c') 728 vim.treesitter.highlighter.new(parser, { 729 queries = { 730 c = hl_query_c .. '\n((translation_unit) @constant (#set! "priority" 101))\n', 731 }, 732 }) 733 end) 734 -- expect everything to have Constant highlight 735 screen:expect { 736 grid = [[ 737 {12:int}{8: x = INT_MAX;} | 738 {8:#define READ_STRING(x, y) (}{12:char}{8: *)read_string((x), (}{12:size_t}{8:)(y))} | 739 {8:#define foo }{12:void}{8: main() { \} | 740 {8: }{12:return}{8: 42; \} | 741 {8: }} | 742 ^ | 743 {1:~ }|*11 744 | 745 ]], 746 attr_ids = { 747 [1] = { bold = true, foreground = Screen.colors.Blue1 }, 748 [8] = { foreground = Screen.colors.Magenta1 }, 749 -- bold will not be overwritten at the moment 750 [12] = { bold = true, foreground = Screen.colors.Magenta1 }, 751 }, 752 } 753 754 eq({ 755 { 756 capture = 'constant', 757 metadata = { priority = '101' }, 758 lang = 'c', 759 id = 14, 760 pattern_id = 23, 761 }, 762 { capture = 'type', metadata = {}, lang = 'c', id = 3, pattern_id = 16 }, 763 }, exec_lua [[ return vim.treesitter.get_captures_at_pos(0, 0, 2) ]]) 764 end) 765 766 it( 767 "allows to use captures with dots (don't use fallback when specialization of foo exists)", 768 function() 769 insert([[ 770 char* x = "Will somebody ever read this?"; 771 ]]) 772 773 screen:expect { 774 grid = [[ 775 char* x = "Will somebody ever read this?"; | 776 ^ | 777 {1:~ }|*15 778 | 779 ]], 780 } 781 782 command [[ 783 hi link @foo.bar Type 784 hi link @foo String 785 ]] 786 exec_lua(function() 787 local parser = vim.treesitter.get_parser(0, 'c', {}) 788 local highlighter = vim.treesitter.highlighter 789 highlighter.new( 790 parser, 791 { queries = { c = '(primitive_type) @foo.bar (string_literal) @foo' } } 792 ) 793 end) 794 795 screen:expect({ 796 grid = [[ 797 {6:char}* x = {26:"Will somebody ever read this?"}; | 798 ^ | 799 {1:~ }|*15 800 | 801 ]], 802 }) 803 804 -- clearing specialization reactivates fallback 805 command [[ hi clear @foo.bar ]] 806 screen:expect({ 807 grid = [[ 808 {26:char}* x = {26:"Will somebody ever read this?"}; | 809 ^ | 810 {1:~ }|*15 811 | 812 ]], 813 }) 814 end 815 ) 816 817 it('supports conceal attribute', function() 818 insert(hl_text_c) 819 820 -- conceal can be empty or a single cchar. 821 exec_lua(function() 822 vim.opt.cole = 2 823 local parser = vim.treesitter.get_parser(0, 'c') 824 vim.treesitter.highlighter.new(parser, { 825 queries = { 826 c = [[ 827 ("static" @keyword 828 (#set! conceal "R")) 829 830 ((identifier) @Identifier 831 (#set! conceal "") 832 (#eq? @Identifier "lstate")) 833 834 ((call_expression 835 function: (identifier) @function 836 arguments: (argument_list) @arguments) 837 (#eq? @function "multiqueue_put") 838 (#set! @function conceal "V")) 839 ]], 840 }, 841 }) 842 end) 843 844 screen:expect({ 845 grid = [[ 846 /// Schedule Lua callback on main loop's event queue | 847 {15:R} int nlua_schedule(lua_State *const ) | 848 { | 849 if (lua_type(, 1) != LUA_TFUNCTION | 850 || != ) { | 851 lua_pushliteral(, "vim.schedule: expected function"); | 852 return lua_error(); | 853 } | 854 | 855 LuaRef cb = nlua_ref(, 1); | 856 | 857 {25:V}(main_loop.events, nlua_schedule_event, | 858 1, (void *)(ptrdiff_t)cb); | 859 return 0; | 860 ^} | 861 {1:~ }|*2 862 | 863 ]], 864 }) 865 end) 866 867 it('@foo.bar groups has the correct fallback behavior', function() 868 local get_hl = function(name) 869 return api.nvim_get_hl_by_name(name, 1).foreground 870 end 871 api.nvim_set_hl(0, '@foo', { fg = 1 }) 872 api.nvim_set_hl(0, '@foo.bar', { fg = 2 }) 873 api.nvim_set_hl(0, '@foo.bar.baz', { fg = 3 }) 874 875 eq(1, get_hl '@foo') 876 eq(1, get_hl '@foo.a.b.c.d') 877 eq(2, get_hl '@foo.bar') 878 eq(2, get_hl '@foo.bar.a.b.c.d') 879 eq(3, get_hl '@foo.bar.baz') 880 eq(3, get_hl '@foo.bar.baz.d') 881 882 -- lookup is case insensitive 883 eq(2, get_hl '@FOO.BAR.SPAM') 884 885 api.nvim_set_hl(0, '@foo.missing.exists', { fg = 3 }) 886 eq(1, get_hl '@foo.missing') 887 eq(3, get_hl '@foo.missing.exists') 888 eq(3, get_hl '@foo.missing.exists.bar') 889 eq(nil, get_hl '@total.nonsense.but.a.lot.of.dots') 890 end) 891 892 it('supports multiple nodes assigned to the same capture #17060', function() 893 insert([[ 894 int x = 4; 895 int y = 5; 896 int z = 6; 897 ]]) 898 899 exec_lua(function() 900 local query = '((declaration)+ @string)' 901 vim.treesitter.query.set('c', 'highlights', query) 902 vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c')) 903 end) 904 905 screen:expect({ 906 grid = [[ 907 {26:int x = 4;} | 908 {26:int y = 5;} | 909 {26:int z = 6;} | 910 ^ | 911 {1:~ }|*13 912 | 913 ]], 914 }) 915 end) 916 917 it('gives higher priority to more specific captures #27895', function() 918 insert([[ 919 void foo(int *bar); 920 ]]) 921 922 local query = [[ 923 "*" @operator 924 925 (parameter_declaration 926 declarator: (pointer_declarator) @variable.parameter) 927 ]] 928 929 exec_lua(function() 930 vim.treesitter.query.set('c', 'highlights', query) 931 vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c')) 932 end) 933 934 screen:expect({ 935 grid = [[ 936 void foo(int {15:*}{25:bar}); | 937 ^ | 938 {1:~ }|*15 939 | 940 ]], 941 }) 942 end) 943 944 it('highlights applied to first line of closed fold', function() 945 insert(hl_text_c) 946 exec_lua(function() 947 vim.treesitter.query.set('c', 'highlights', hl_query_c) 948 vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c')) 949 end) 950 feed('ggjzfj') 951 command('set foldtext=') 952 screen:add_extra_attr_ids({ 953 [100] = { 954 bold = true, 955 background = Screen.colors.LightGray, 956 foreground = Screen.colors.SeaGreen4, 957 }, 958 [101] = { background = Screen.colors.LightGray, foreground = Screen.colors.DarkCyan }, 959 }) 960 screen:expect({ 961 grid = [[ 962 {18:/// Schedule Lua callback on main loop's event queue} | 963 {100:^static}{13: }{100:int}{13: }{101:nlua_schedule}{13:(}{100:lua_State}{13: *}{100:const}{13: lstate)················}| 964 {15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} | 965 || {19:lstate} != {19:lstate}) { | 966 {25:lua_pushliteral}(lstate, {26:"vim.schedule: expected function"}); | 967 {15:return} {25:lua_error}(lstate); | 968 } | 969 | 970 {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); | 971 | 972 multiqueue_put(main_loop.events, {25:nlua_schedule_event}, | 973 {26:1}, ({6:void} *)({6:ptrdiff_t})cb); | 974 {15:return} {26:0}; | 975 } | 976 {1:~ }|*3 977 | 978 ]], 979 }) 980 end) 981 end) 982 983 describe('treesitter highlighting (lua)', function() 984 local screen 985 986 before_each(function() 987 clear() 988 screen = Screen.new(65, 18) 989 end) 990 991 it('supports language injections', function() 992 insert [[ 993 local ffi = require('ffi') 994 ffi.cdef("int (*fun)(int, char *);") 995 ]] 996 997 exec_lua(function() 998 vim.bo.filetype = 'lua' 999 vim.treesitter.start() 1000 end) 1001 1002 screen:expect({ 1003 grid = [[ 1004 {15:local} {25:ffi} {15:=} {16:require(}{26:'ffi'}{16:)} | 1005 {25:ffi}{16:.}{25:cdef}{16:(}{26:"}{16:int}{26: }{16:(}{15:*}{26:fun}{16:)(int,}{26: }{16:char}{26: }{15:*}{16:);}{26:"}{16:)} | 1006 ^ | 1007 {1:~ }|*14 1008 | 1009 ]], 1010 }) 1011 end) 1012 1013 it('removes outdated highlights', function() 1014 insert('-- int main() {}' .. string.rep("\nprint('test')", 20) .. '\n-- int other() {}') 1015 1016 exec_lua(function() 1017 vim.cmd.norm('gg') 1018 vim.treesitter.query.set( 1019 'lua', 1020 'injections', 1021 [[((comment_content) @injection.content 1022 (#set! injection.combined) 1023 (#set! injection.language "c"))]] 1024 ) 1025 vim.bo.filetype = 'lua' 1026 vim.treesitter.start() 1027 end) 1028 1029 screen:expect([[ 1030 {18:^-- }{16:int}{18: }{25:main}{16:()}{18: }{16:{}} | 1031 {16:print(}{26:'test'}{16:)} |*16 1032 | 1033 ]]) 1034 1035 exec_lua(function() 1036 vim.cmd.norm('gg0dw') 1037 end) 1038 1039 screen:expect([[ 1040 {25:^int} {25:main}{16:()} {16:{}} | 1041 {16:print(}{26:'test'}{16:)} |*16 1042 | 1043 ]]) 1044 end) 1045 end) 1046 1047 describe('treesitter highlighting (help)', function() 1048 local screen 1049 1050 before_each(function() 1051 clear() 1052 screen = Screen.new(40, 6) 1053 end) 1054 1055 it('defaults in vimdoc/highlights.scm', function() 1056 -- Avoid regressions when syncing upstream vimdoc queries. 1057 1058 insert [[ 1059 ============================================================================== 1060 NVIM DOCUMENTATION 1061 1062 ------------------------------------------------------------------------------ 1063 ABOUT NVIM *tag-1* *tag-2* 1064 1065 |news| News 1066 |nvim| NVim 1067 ]] 1068 1069 feed('gg') 1070 exec_lua(function() 1071 vim.wo.wrap = false 1072 vim.bo.filetype = 'help' 1073 vim.treesitter.start() 1074 end) 1075 1076 screen:add_extra_attr_ids({ 1077 [100] = { nocombine = true, underdouble = true }, 1078 [101] = { foreground = Screen.colors.Fuchsia, bold = true }, 1079 [102] = { underline = true, nocombine = true }, 1080 }) 1081 screen:expect({ 1082 grid = [[ 1083 {100:^========================================}| 1084 {101:NVIM DOCUMENTATION} | 1085 | 1086 {102:----------------------------------------}| 1087 {101:ABOUT NVIM} | 1088 | 1089 ]], 1090 }) 1091 end) 1092 1093 it('correctly redraws added/removed injections', function() 1094 insert [[ 1095 >ruby 1096 -- comment 1097 local this_is = 'actually_lua' 1098 < 1099 ]] 1100 1101 exec_lua(function() 1102 vim.bo.filetype = 'help' 1103 vim.treesitter.start() 1104 end) 1105 1106 screen:expect({ 1107 grid = [[ 1108 {18:>}{15:ruby} | 1109 {18: -- comment} | 1110 {18: local this_is = 'actually_lua'} | 1111 {18:<} | 1112 ^ | 1113 | 1114 ]], 1115 }) 1116 1117 n.api.nvim_buf_set_text(0, 0, 1, 0, 5, { 'lua' }) 1118 1119 screen:expect({ 1120 grid = [[ 1121 {18:>}{15:lua} | 1122 {18: -- comment} | 1123 {18: }{15:local}{18: }{25:this_is}{18: }{15:=}{18: }{26:'actually_lua'} | 1124 {18:<} | 1125 ^ | 1126 | 1127 ]], 1128 }) 1129 1130 n.api.nvim_buf_set_text(0, 0, 1, 0, 4, { 'ruby' }) 1131 1132 screen:expect({ 1133 grid = [[ 1134 {18:>}{15:ruby} | 1135 {18: -- comment} | 1136 {18: local this_is = 'actually_lua'} | 1137 {18:<} | 1138 ^ | 1139 | 1140 ]], 1141 }) 1142 end) 1143 1144 it('correctly redraws injections subpriorities', function() 1145 -- The top level string node will be highlighted first 1146 -- with an extmark spanning multiple lines. 1147 -- When the next line is drawn, which includes an injection, 1148 -- make sure the highlight appears above the base tree highlight 1149 1150 insert([=[ 1151 local s = [[ 1152 local also = lua 1153 ]] 1154 ]=]) 1155 1156 exec_lua(function() 1157 local parser = vim.treesitter.get_parser(0, 'lua', { 1158 injections = { 1159 lua = '(string content: (_) @injection.content (#set! injection.language lua))', 1160 }, 1161 }) 1162 1163 vim.treesitter.highlighter.new(parser) 1164 end) 1165 1166 screen:expect({ 1167 grid = [=[ 1168 {15:local} {25:s} {15:=} {26:[[} | 1169 {26: }{15:local}{26: }{25:also}{26: }{15:=}{26: }{25:lua} | 1170 {26:]]} | 1171 ^ | 1172 {1:~ }| 1173 | 1174 ]=], 1175 }) 1176 end) 1177 end) 1178 1179 describe('treesitter highlighting (nested injections)', function() 1180 local screen --- @type test.functional.ui.screen 1181 1182 before_each(function() 1183 clear() 1184 screen = Screen.new(80, 7) 1185 end) 1186 1187 it('correctly redraws nested injections (GitHub #25252)', function() 1188 insert [=[ 1189 function foo() print("Lua!") end 1190 1191 local lorem = { 1192 ipsum = {}, 1193 bar = {}, 1194 } 1195 vim.cmd([[ 1196 augroup RustLSP 1197 autocmd CursorHold silent! lua vim.lsp.buf.document_highlight() 1198 augroup END 1199 ]]) 1200 ]=] 1201 1202 exec_lua(function() 1203 vim.opt.scrolloff = 0 1204 vim.bo.filetype = 'lua' 1205 vim.treesitter.start() 1206 end) 1207 1208 -- invalidate the language tree 1209 feed('ggi--[[<ESC>04x') 1210 1211 screen:expect({ 1212 grid = [[ 1213 {15:^function} {25:foo}{16:()} {16:print(}{26:"Lua!"}{16:)} {15:end} | 1214 | 1215 {15:local} {25:lorem} {15:=} {16:{} | 1216 {25:ipsum} {15:=} {16:{},} | 1217 {25:bar} {15:=} {16:{},} | 1218 {16:}} | 1219 | 1220 ]], 1221 }) 1222 1223 -- spam newline insert/delete to invalidate Lua > Vim > Lua region 1224 feed('3jo<ESC>ddko<ESC>ddko<ESC>ddko<ESC>ddk0') 1225 1226 screen:expect({ 1227 grid = [[ 1228 {15:function} {25:foo}{16:()} {16:print(}{26:"Lua!"}{16:)} {15:end} | 1229 | 1230 {15:local} {25:lorem} {15:=} {16:{} | 1231 ^ {25:ipsum} {15:=} {16:{},} | 1232 {25:bar} {15:=} {16:{},} | 1233 {16:}} | 1234 | 1235 ]], 1236 }) 1237 end) 1238 end) 1239 1240 describe('treesitter highlighting (markdown)', function() 1241 local screen 1242 1243 before_each(function() 1244 clear() 1245 screen = Screen.new(40, 6) 1246 exec_lua(function() 1247 vim.bo.filetype = 'markdown' 1248 vim.treesitter.start() 1249 end) 1250 end) 1251 1252 it('supports hyperlinks', function() 1253 local url = 'https://example.com' 1254 insert(string.format('[This link text](%s) is a hyperlink.', url)) 1255 screen:add_extra_attr_ids({ 1256 [100] = { foreground = Screen.colors.DarkCyan, url = 'https://example.com' }, 1257 [101] = { 1258 foreground = Screen.colors.SlateBlue, 1259 url = 'https://example.com', 1260 underline = true, 1261 }, 1262 }) 1263 screen:expect({ 1264 grid = [[ 1265 {100:[This link text](}{101:https://example.com}{100:)} is| 1266 a hyperlink^. | 1267 {1:~ }|*3 1268 | 1269 ]], 1270 }) 1271 end) 1272 1273 local code_block = [[ 1274 - $f(0)=\sum_{k=1}^{\infty}\frac{2}{\pi^{2}k^{2}}+\lim_{w \to 0}x$. 1275 1276 ```c 1277 printf('Hello World!'); 1278 ``` 1279 ]] 1280 1281 it('works with spellchecked and smoothscrolled topline', function() 1282 insert(code_block) 1283 command('set spell smoothscroll') 1284 feed('gg<C-E>') 1285 screen:add_extra_attr_ids({ [100] = { undercurl = true, special = Screen.colors.Red } }) 1286 screen:expect({ 1287 grid = [[ 1288 {1:<<<}k^{2}}+\{100:lim}_{w \to 0}x$^. | 1289 | 1290 {18:```}{15:c} | 1291 {25:printf}{16:(}{26:'Hello World!'}{16:);} | 1292 {18:```} | 1293 | 1294 ]], 1295 }) 1296 end) 1297 1298 it('works with concealed lines', function() 1299 insert(code_block) 1300 screen:expect({ 1301 grid = [[ 1302 | 1303 {18:```}{15:c} | 1304 {25:printf}{16:(}{26:'Hello World!'}{16:);} | 1305 {18:```} | 1306 ^ | 1307 | 1308 ]], 1309 }) 1310 feed('ggj') 1311 command('set number conceallevel=3') 1312 screen:expect({ 1313 grid = [[ 1314 {8: 1 }{16:- }$f(0)=\sum_{k=1}^{\infty}\frac{2}{| 1315 {8: }\pi^{2}k^{2}}+\lim_{w \to 0}x$. | 1316 {8: 2 }^ | 1317 {8: 4 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1318 {8: 6 } | 1319 | 1320 ]], 1321 }) 1322 feed('j') 1323 screen:expect({ 1324 grid = [[ 1325 {8: 1 }{16:- }$f(0)=\sum_{k=1}^{\infty}\frac{2}{| 1326 {8: }\pi^{2}k^{2}}+\lim_{w \to 0}x$. | 1327 {8: 2 } | 1328 {8: 3 }{18:^```}{15:c} | 1329 {8: 4 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1330 | 1331 ]], 1332 }) 1333 feed('j') 1334 screen:expect({ 1335 grid = [[ 1336 {8: 1 }{16:- }$f(0)=\sum_{k=1}^{\infty}\frac{2}{| 1337 {8: }\pi^{2}k^{2}}+\lim_{w \to 0}x$. | 1338 {8: 2 } | 1339 {8: 4 }{25:^printf}{16:(}{26:'Hello World!'}{16:);} | 1340 {8: 6 } | 1341 | 1342 ]], 1343 }) 1344 feed('j') 1345 screen:expect({ 1346 grid = [[ 1347 {8: 1 }{16:- }$f(0)=\sum_{k=1}^{\infty}\frac{2}{| 1348 {8: }\pi^{2}k^{2}}+\lim_{w \to 0}x$. | 1349 {8: 2 } | 1350 {8: 4 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1351 {8: 5 }{18:^```} | 1352 | 1353 ]], 1354 }) 1355 -- Concealed lines highlight until changed botline 1356 screen:try_resize(screen._width, 16) 1357 feed('y3k30P:<Esc><C-F><C-B>') 1358 screen:expect([[ 1359 {8: 1 }{16:- }$f(0)=\sum_{k=1}^{\infty}\frac{2}{| 1360 {8: }\pi^{2}k^{2}}+\lim_{w \to 0}x$. | 1361 {8: 2 } | 1362 {8: 4 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1363 {8: 6 } | 1364 {8: 8 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1365 {8: 10 } | 1366 {8: 12 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1367 {8: 14 } | 1368 {8: 16 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1369 {8: 18 } | 1370 {8: 20 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1371 {8: 22 } | 1372 {8: 24 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1373 {8: 25 }{18:^```} | 1374 | 1375 ]]) 1376 feed('G') 1377 screen:expect([[ 1378 {8: 98 } | 1379 {8:100 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1380 {8:102 } | 1381 {8:104 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1382 {8:106 } | 1383 {8:108 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1384 {8:110 } | 1385 {8:112 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1386 {8:114 } | 1387 {8:116 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1388 {8:118 } | 1389 {8:120 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1390 {8:122 } | 1391 {8:124 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1392 {8:126 }^ | 1393 | 1394 ]]) 1395 feed('ggdj') 1396 command('set concealcursor=n') 1397 screen:expect([[ 1398 {8: 2 }{25:^printf}{16:(}{26:'Hello World!'}{16:);} | 1399 {8: 4 } | 1400 {8: 6 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1401 {8: 8 } | 1402 {8: 10 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1403 {8: 12 } | 1404 {8: 14 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1405 {8: 16 } | 1406 {8: 18 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1407 {8: 20 } | 1408 {8: 22 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1409 {8: 24 } | 1410 {8: 26 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1411 {8: 28 } | 1412 {8: 30 }{25:printf}{16:(}{26:'Hello World!'}{16:);} | 1413 | 1414 ]]) 1415 exec_lua(function() 1416 vim.api.nvim_buf_set_lines(0, 0, -1, false, {}) 1417 assert(vim.api.nvim_win_text_height(0, {}).all == 1, 'line concealed') 1418 end) 1419 end) 1420 end) 1421 1422 it('starting and stopping treesitter highlight in init.lua works #29541', function() 1423 t.write_file( 1424 'Xinit.lua', 1425 [[ 1426 vim.bo.ft = 'c' 1427 vim.treesitter.start() 1428 vim.treesitter.stop() 1429 ]] 1430 ) 1431 finally(function() 1432 os.remove('Xinit.lua') 1433 end) 1434 clear({ args = { '-u', 'Xinit.lua' } }) 1435 eq('', api.nvim_get_vvar('errmsg')) 1436 1437 local screen = Screen.new(65, 18) 1438 fn.setreg('r', hl_text_c) 1439 feed('i<C-R><C-O>r<Esc>gg') 1440 -- legacy syntax highlighting is used 1441 screen:expect(hl_grid_legacy_c) 1442 end) 1443 1444 it('no nil index for missing highlight query', function() 1445 clear() 1446 local cqueries = t.paths.test_source_path .. '/runtime/queries/c/' 1447 os.rename(cqueries .. 'highlights.scm', cqueries .. '_highlights.scm') 1448 finally(function() 1449 os.rename(cqueries .. '_highlights.scm', cqueries .. 'highlights.scm') 1450 end) 1451 exec_lua([[ 1452 local parser = vim.treesitter.get_parser(0, 'c') 1453 vim.treesitter.highlighter.new(parser) 1454 ]]) 1455 end) 1456 1457 it('spell navigation correctly wraps back to the first line (Row 0) #36970', function() 1458 clear() 1459 insert([[ 1460 mispelledone 1461 mispelledtwo]]) 1462 1463 command('set spell') 1464 command('set wrapscan') 1465 exec_lua(function() 1466 vim.treesitter.start(0, 'markdown') 1467 end) 1468 1469 api.nvim_win_set_cursor(0, { 2, 0 }) 1470 1471 feed(']s') 1472 1473 local pos = api.nvim_win_get_cursor(0) 1474 eq(1, pos[1], 'Should have wrapped back to Line 1') 1475 end)