diagnostic_spec.lua (145115B)
1 local t = require('test.testutil') 2 local n = require('test.functional.testnvim')() 3 4 local command = n.command 5 local clear = n.clear 6 local exec_lua = n.exec_lua 7 local eq = t.eq 8 local neq = t.neq 9 local matches = t.matches 10 local retry = t.retry 11 local api = n.api 12 local pcall_err = t.pcall_err 13 local fn = n.fn 14 15 describe('vim.diagnostic', function() 16 before_each(function() 17 clear() 18 19 exec_lua(function() 20 require('vim.diagnostic') 21 22 local function make_diagnostic(msg, lnum, col, end_lnum, end_col, severity, source, code) 23 return { 24 lnum = lnum, 25 col = col, 26 end_lnum = end_lnum, 27 end_col = end_col, 28 message = msg, 29 severity = severity, 30 source = source, 31 code = code, 32 } 33 end 34 35 function _G.make_error(msg, lnum, col, end_lnum, end_col, source, code) 36 return make_diagnostic( 37 msg, 38 lnum, 39 col, 40 end_lnum, 41 end_col, 42 vim.diagnostic.severity.ERROR, 43 source, 44 code 45 ) 46 end 47 48 function _G.make_warning(msg, lnum, col, end_lnum, end_col, source, code) 49 return make_diagnostic( 50 msg, 51 lnum, 52 col, 53 end_lnum, 54 end_col, 55 vim.diagnostic.severity.WARN, 56 source, 57 code 58 ) 59 end 60 61 function _G.make_info(msg, lnum, col, end_lnum, end_col, source, code) 62 return make_diagnostic( 63 msg, 64 lnum, 65 col, 66 end_lnum, 67 end_col, 68 vim.diagnostic.severity.INFO, 69 source, 70 code 71 ) 72 end 73 74 function _G.make_hint(msg, lnum, col, end_lnum, end_col, source, code) 75 return make_diagnostic( 76 msg, 77 lnum, 78 col, 79 end_lnum, 80 end_col, 81 vim.diagnostic.severity.HINT, 82 source, 83 code 84 ) 85 end 86 87 function _G.count_diagnostics(bufnr, severity, namespace) 88 return #vim.diagnostic.get(bufnr, { severity = severity, namespace = namespace }) 89 end 90 91 function _G.count_extmarks(bufnr, namespace) 92 local ns = vim.diagnostic.get_namespace(namespace) 93 local extmarks = 0 94 if ns.user_data.virt_text_ns then 95 extmarks = extmarks 96 + #vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {}) 97 end 98 if ns.user_data.underline_ns then 99 extmarks = extmarks 100 + #vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {}) 101 end 102 return extmarks 103 end 104 105 function _G.get_virt_text_extmarks(ns) 106 ns = vim.diagnostic.get_namespace(ns) 107 local virt_text_ns = ns.user_data.virt_text_ns 108 return vim.api.nvim_buf_get_extmarks( 109 _G.diagnostic_bufnr, 110 virt_text_ns, 111 0, 112 -1, 113 { details = true } 114 ) 115 end 116 117 function _G.get_virt_lines_extmarks(ns) 118 ns = vim.diagnostic.get_namespace(ns) 119 local virt_lines_ns = ns.user_data.virt_lines_ns 120 return vim.api.nvim_buf_get_extmarks( 121 _G.diagnostic_bufnr, 122 virt_lines_ns, 123 0, 124 -1, 125 { details = true } 126 ) 127 end 128 129 ---@param ns integer 130 function _G.get_underline_extmarks(ns) 131 ---@type integer 132 local underline_ns = vim.diagnostic.get_namespace(ns).user_data.underline_ns 133 return vim.api.nvim_buf_get_extmarks( 134 _G.diagnostic_bufnr, 135 underline_ns, 136 0, 137 -1, 138 { details = true } 139 ) 140 end 141 end) 142 143 exec_lua(function() 144 _G.diagnostic_ns = vim.api.nvim_create_namespace('diagnostic_spec') 145 _G.other_ns = vim.api.nvim_create_namespace('other_namespace') 146 _G.diagnostic_bufnr = vim.api.nvim_create_buf(true, false) 147 local lines = { '1st line of text', '2nd line of text', 'wow', 'cool', 'more', 'lines' } 148 vim.fn.bufload(_G.diagnostic_bufnr) 149 vim.api.nvim_buf_set_lines(_G.diagnostic_bufnr, 0, 1, false, lines) 150 end) 151 end) 152 153 it('creates highlight groups', function() 154 command('runtime plugin/diagnostic.vim') 155 eq({ 156 'DiagnosticDeprecated', 157 'DiagnosticError', 158 'DiagnosticFloatingError', 159 'DiagnosticFloatingHint', 160 'DiagnosticFloatingInfo', 161 'DiagnosticFloatingOk', 162 'DiagnosticFloatingWarn', 163 'DiagnosticHint', 164 'DiagnosticInfo', 165 'DiagnosticOk', 166 'DiagnosticSignError', 167 'DiagnosticSignHint', 168 'DiagnosticSignInfo', 169 'DiagnosticSignOk', 170 'DiagnosticSignWarn', 171 'DiagnosticUnderlineError', 172 'DiagnosticUnderlineHint', 173 'DiagnosticUnderlineInfo', 174 'DiagnosticUnderlineOk', 175 'DiagnosticUnderlineWarn', 176 'DiagnosticUnnecessary', 177 'DiagnosticVirtualLinesError', 178 'DiagnosticVirtualLinesHint', 179 'DiagnosticVirtualLinesInfo', 180 'DiagnosticVirtualLinesOk', 181 'DiagnosticVirtualLinesWarn', 182 'DiagnosticVirtualTextError', 183 'DiagnosticVirtualTextHint', 184 'DiagnosticVirtualTextInfo', 185 'DiagnosticVirtualTextOk', 186 'DiagnosticVirtualTextWarn', 187 'DiagnosticWarn', 188 }, fn.getcompletion('Diagnostic', 'highlight')) 189 end) 190 191 it('retrieves diagnostics from all buffers and namespaces', function() 192 local result = exec_lua(function() 193 local other_bufnr = vim.api.nvim_create_buf(true, false) 194 local lines = vim.api.nvim_buf_get_lines(_G.diagnostic_bufnr, 0, -1, true) 195 vim.api.nvim_buf_set_lines(other_bufnr, 0, 1, false, lines) 196 197 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 198 _G.make_error('Diagnostic #1', 1, 1, 1, 1), 199 _G.make_error('Diagnostic #2', 2, 1, 2, 1), 200 }) 201 vim.diagnostic.set(_G.other_ns, other_bufnr, { 202 _G.make_error('Diagnostic #3', 3, 1, 3, 1), 203 }) 204 return vim.diagnostic.get() 205 end) 206 eq(3, #result) 207 eq( 208 2, 209 exec_lua(function() 210 return #vim.tbl_filter(function(d) 211 return d.bufnr == _G.diagnostic_bufnr 212 end, result) 213 end) 214 ) 215 eq('Diagnostic #1', result[1].message) 216 end) 217 218 it('removes diagnostics from the cache when a buffer is removed', function() 219 eq( 220 2, 221 exec_lua(function() 222 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 223 local other_bufnr = vim.fn.bufadd('test | test') 224 local lines = vim.api.nvim_buf_get_lines(_G.diagnostic_bufnr, 0, -1, true) 225 vim.api.nvim_buf_set_lines(other_bufnr, 0, 1, false, lines) 226 vim.cmd('bunload! ' .. other_bufnr) 227 228 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 229 _G.make_error('Diagnostic #1', 1, 1, 1, 1), 230 _G.make_error('Diagnostic #2', 2, 1, 2, 1), 231 }) 232 vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, { 233 _G.make_error('Diagnostic #3', 3, 1, 3, 1), 234 }) 235 vim.api.nvim_set_current_buf(other_bufnr) 236 vim.opt_local.buflisted = true 237 vim.cmd('bwipeout!') 238 return #vim.diagnostic.get() 239 end) 240 ) 241 eq( 242 2, 243 exec_lua(function() 244 vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) 245 vim.opt_local.buflisted = false 246 return #vim.diagnostic.get() 247 end) 248 ) 249 eq( 250 0, 251 exec_lua(function() 252 vim.cmd('bwipeout!') 253 return #vim.diagnostic.get() 254 end) 255 ) 256 end) 257 258 it('removes diagnostic from stale cache on reset', function() 259 local diagnostics = exec_lua(function() 260 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 261 _G.make_error('Diagnostic #1', 1, 1, 1, 1), 262 _G.make_error('Diagnostic #2', 2, 1, 2, 1), 263 }) 264 vim.fn.bufadd('test | test') 265 vim.cmd('noautocmd bwipeout! ' .. _G.diagnostic_bufnr) 266 return vim.diagnostic.get(_G.diagnostic_bufnr) 267 end) 268 eq(2, #diagnostics) 269 diagnostics = exec_lua(function() 270 vim.diagnostic.reset() 271 return vim.diagnostic.get() 272 end) 273 eq(0, #diagnostics) 274 end) 275 276 it('always returns a copy of diagnostic tables', function() 277 local result = exec_lua(function() 278 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 279 _G.make_error('Diagnostic #1', 1, 1, 1, 1), 280 }) 281 local diag = vim.diagnostic.get() 282 diag[1].col = 10000 283 return vim.diagnostic.get()[1].col == 10000 284 end) 285 eq(false, result) 286 end) 287 288 it('resolves buffer number 0 to the current buffer', function() 289 eq( 290 2, 291 exec_lua(function() 292 vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) 293 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 294 _G.make_error('Diagnostic #1', 1, 1, 1, 1), 295 _G.make_error('Diagnostic #2', 2, 1, 2, 1), 296 }) 297 return #vim.diagnostic.get(0) 298 end) 299 ) 300 end) 301 302 it('saves and count a single error', function() 303 eq( 304 1, 305 exec_lua(function() 306 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 307 _G.make_error('Diagnostic #1', 1, 1, 1, 1), 308 }) 309 return _G.count_diagnostics( 310 _G.diagnostic_bufnr, 311 vim.diagnostic.severity.ERROR, 312 _G.diagnostic_ns 313 ) 314 end) 315 ) 316 end) 317 318 it('saves and count multiple errors', function() 319 eq( 320 2, 321 exec_lua(function() 322 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 323 _G.make_error('Diagnostic #1', 1, 1, 1, 1), 324 _G.make_error('Diagnostic #2', 2, 1, 2, 1), 325 }) 326 return _G.count_diagnostics( 327 _G.diagnostic_bufnr, 328 vim.diagnostic.severity.ERROR, 329 _G.diagnostic_ns 330 ) 331 end) 332 ) 333 end) 334 335 it('saves and count from multiple namespaces', function() 336 eq( 337 { 1, 1, 2 }, 338 exec_lua(function() 339 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 340 _G.make_error('Diagnostic From Server 1', 1, 1, 1, 1), 341 }) 342 vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, { 343 _G.make_error('Diagnostic From Server 2', 1, 1, 1, 1), 344 }) 345 return { 346 -- First namespace 347 _G.count_diagnostics( 348 _G.diagnostic_bufnr, 349 vim.diagnostic.severity.ERROR, 350 _G.diagnostic_ns 351 ), 352 -- Second namespace 353 _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.other_ns), 354 -- All namespaces 355 _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR), 356 } 357 end) 358 ) 359 end) 360 361 it('saves and count from multiple namespaces with respect to severity', function() 362 eq( 363 { 3, 0, 3 }, 364 exec_lua(function() 365 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 366 _G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), 367 _G.make_error('Diagnostic From Server 1:2', 2, 2, 2, 2), 368 _G.make_error('Diagnostic From Server 1:3', 2, 3, 3, 2), 369 }) 370 vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, { 371 _G.make_warning('Warning From Server 2', 3, 3, 3, 3), 372 }) 373 return { 374 -- Namespace 1 375 _G.count_diagnostics( 376 _G.diagnostic_bufnr, 377 vim.diagnostic.severity.ERROR, 378 _G.diagnostic_ns 379 ), 380 -- Namespace 2 381 _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.other_ns), 382 -- All namespaces 383 _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR), 384 } 385 end) 386 ) 387 end) 388 389 it('handles one namespace clearing highlights while the other still has highlights', function() 390 exec_lua(function() 391 vim.diagnostic.config({ virtual_text = true }) 392 end) 393 -- 1 Error (1) 394 -- 1 Warning (2) 395 -- 1 Warning (2) + 1 Warning (1) 396 -- 2 highlights and 2 underlines (since error) 397 -- 1 highlight + 1 underline 398 local all_highlights = { 1, 1, 2, 4, 2 } 399 eq( 400 all_highlights, 401 exec_lua(function() 402 local ns_1_diags = { 403 _G.make_error('Error 1', 1, 1, 1, 5), 404 _G.make_warning('Warning on Server 1', 2, 1, 2, 3), 405 } 406 local ns_2_diags = { 407 _G.make_warning('Warning 1', 2, 1, 2, 3), 408 } 409 410 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) 411 vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) 412 413 return { 414 _G.count_diagnostics( 415 _G.diagnostic_bufnr, 416 vim.diagnostic.severity.ERROR, 417 _G.diagnostic_ns 418 ), 419 _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), 420 _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), 421 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), 422 _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), 423 } 424 end) 425 ) 426 427 -- Clear diagnostics from namespace 1, and make sure we have the right amount of stuff for namespace 2 428 eq( 429 { 1, 1, 2, 0, 2 }, 430 exec_lua(function() 431 vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) 432 return { 433 _G.count_diagnostics( 434 _G.diagnostic_bufnr, 435 vim.diagnostic.severity.ERROR, 436 _G.diagnostic_ns 437 ), 438 _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), 439 _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), 440 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), 441 _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), 442 } 443 end) 444 ) 445 446 -- Show diagnostics from namespace 1 again 447 eq( 448 all_highlights, 449 exec_lua(function() 450 vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) 451 return { 452 _G.count_diagnostics( 453 _G.diagnostic_bufnr, 454 vim.diagnostic.severity.ERROR, 455 _G.diagnostic_ns 456 ), 457 _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), 458 _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), 459 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), 460 _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), 461 } 462 end) 463 ) 464 end) 465 466 it('does not display diagnostics when disabled', function() 467 exec_lua(function() 468 vim.diagnostic.config({ virtual_text = true }) 469 end) 470 471 eq( 472 { 0, 2 }, 473 exec_lua(function() 474 local ns_1_diags = { 475 _G.make_error('Error 1', 1, 1, 1, 5), 476 _G.make_warning('Warning on Server 1', 2, 1, 2, 3), 477 } 478 local ns_2_diags = { 479 _G.make_warning('Warning 1', 2, 1, 2, 3), 480 } 481 482 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) 483 vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) 484 485 vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) 486 487 return { 488 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), 489 _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), 490 } 491 end) 492 ) 493 494 eq( 495 { 4, 0 }, 496 exec_lua(function() 497 vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) 498 vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.other_ns }) 499 500 return { 501 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), 502 _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), 503 } 504 end) 505 ) 506 end) 507 508 describe('show() and hide()', function() 509 it('works', function() 510 local result = exec_lua(function() 511 local other_bufnr = vim.api.nvim_create_buf(true, false) 512 513 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 514 515 local result = {} 516 517 vim.diagnostic.config({ underline = false, virtual_text = true }) 518 519 local ns_1_diags = { 520 _G.make_error('Error 1', 1, 1, 1, 5), 521 _G.make_warning('Warning on Server 1', 2, 1, 2, 5), 522 } 523 local ns_2_diags = { 524 _G.make_warning('Warning 1', 2, 1, 2, 5), 525 } 526 local other_buffer_diags = { 527 _G.make_info('This is interesting', 0, 0, 0, 0), 528 } 529 530 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) 531 vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) 532 vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags) 533 534 -- All buffers and namespaces 535 table.insert( 536 result, 537 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 538 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 539 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 540 ) 541 542 -- Hide one namespace 543 vim.diagnostic.hide(_G.diagnostic_ns) 544 table.insert( 545 result, 546 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 547 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 548 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 549 ) 550 551 -- Show one namespace 552 vim.diagnostic.show(_G.diagnostic_ns) 553 table.insert( 554 result, 555 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 556 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 557 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 558 ) 559 560 -- Hide one buffer 561 vim.diagnostic.hide(nil, other_bufnr) 562 table.insert( 563 result, 564 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 565 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 566 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 567 ) 568 569 -- Hide everything 570 vim.diagnostic.hide() 571 table.insert( 572 result, 573 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 574 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 575 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 576 ) 577 578 -- Show one buffer 579 vim.diagnostic.show(nil, _G.diagnostic_bufnr) 580 table.insert( 581 result, 582 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 583 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 584 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 585 ) 586 587 return result 588 end) 589 590 eq(4, result[1]) 591 eq(1, result[2]) 592 eq(4, result[3]) 593 eq(3, result[4]) 594 eq(0, result[5]) 595 eq(3, result[6]) 596 end) 597 598 it("doesn't error after bwipeout on buffer", function() 599 exec_lua(function() 600 vim.diagnostic.set( 601 _G.diagnostic_ns, 602 _G.diagnostic_bufnr, 603 { { message = '', lnum = 0, end_lnum = 0, col = 0, end_col = 0 } } 604 ) 605 vim.cmd('bwipeout! ' .. _G.diagnostic_bufnr) 606 607 vim.diagnostic.show(_G.diagnostic_ns) 608 vim.diagnostic.hide(_G.diagnostic_ns) 609 end) 610 end) 611 612 it('handles diagnostics without extmark_id', function() 613 exec_lua(function() 614 vim.diagnostic.config({ virtual_text = true }) 615 616 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 617 _G.make_error('Error message', 0, 0, 0, 5), 618 }) 619 620 local diags = vim.diagnostic.get(_G.diagnostic_bufnr, { namespace = _G.diagnostic_ns }) 621 diags[1]._extmark_id = nil 622 623 vim.diagnostic.show(_G.diagnostic_ns, _G.diagnostic_bufnr, diags) 624 end) 625 end) 626 end) 627 628 describe('enable() and disable()', function() 629 it('validation', function() 630 matches('expected boolean, got table', pcall_err(exec_lua, [[vim.diagnostic.enable({})]])) 631 matches( 632 'filter: expected table, got string', 633 pcall_err(exec_lua, [[vim.diagnostic.enable(false, '')]]) 634 ) 635 matches( 636 'Invalid buffer id: 42', 637 pcall_err(exec_lua, [[vim.diagnostic.enable(true, { bufnr = 42 })]]) 638 ) 639 matches( 640 'expected boolean, got number', 641 pcall_err(exec_lua, [[vim.diagnostic.enable(42, {})]]) 642 ) 643 matches('expected boolean, got table', pcall_err(exec_lua, [[vim.diagnostic.enable({}, 42)]])) 644 end) 645 646 it('without arguments', function() 647 local result = exec_lua(function() 648 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 649 650 local result = {} 651 652 vim.diagnostic.config({ underline = false, virtual_text = true }) 653 654 local ns_1_diags = { 655 _G.make_error('Error 1', 1, 1, 1, 5), 656 _G.make_warning('Warning on Server 1', 2, 1, 2, 5), 657 } 658 local ns_2_diags = { 659 _G.make_warning('Warning 1', 2, 1, 2, 5), 660 } 661 662 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) 663 vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) 664 665 table.insert( 666 result, 667 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 668 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 669 ) 670 671 vim.diagnostic.enable(false) 672 673 table.insert( 674 result, 675 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 676 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 677 ) 678 679 -- Create a new buffer 680 local other_bufnr = vim.api.nvim_create_buf(true, false) 681 local other_buffer_diags = { 682 _G.make_info('This is interesting', 0, 0, 0, 0), 683 } 684 685 vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags) 686 687 table.insert( 688 result, 689 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 690 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 691 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 692 ) 693 694 vim.diagnostic.enable() 695 696 table.insert( 697 result, 698 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 699 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 700 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 701 ) 702 703 return result 704 end) 705 706 eq(3, result[1]) 707 eq(0, result[2]) 708 eq(0, result[3]) 709 eq(4, result[4]) 710 end) 711 712 it('with buffer argument', function() 713 local result = exec_lua(function() 714 local other_bufnr = vim.api.nvim_create_buf(true, false) 715 716 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 717 718 local result = {} 719 720 vim.diagnostic.config({ underline = false, virtual_text = true }) 721 722 local ns_1_diags = { 723 _G.make_error('Error 1', 1, 1, 1, 5), 724 _G.make_warning('Warning on Server 1', 2, 1, 2, 5), 725 } 726 local ns_2_diags = { 727 _G.make_warning('Warning 1', 2, 1, 2, 5), 728 } 729 local other_buffer_diags = { 730 _G.make_info('This is interesting', 0, 0, 0, 0), 731 } 732 733 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) 734 vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) 735 vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags) 736 737 table.insert( 738 result, 739 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 740 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 741 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 742 ) 743 744 vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr }) 745 746 table.insert( 747 result, 748 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 749 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 750 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 751 ) 752 753 vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr }) 754 755 table.insert( 756 result, 757 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 758 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 759 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 760 ) 761 762 vim.diagnostic.enable(false, { bufnr = other_bufnr }) 763 764 table.insert( 765 result, 766 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 767 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 768 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 769 ) 770 771 return result 772 end) 773 774 eq(4, result[1]) 775 eq(1, result[2]) 776 eq(4, result[3]) 777 eq(3, result[4]) 778 end) 779 780 it('with a namespace argument', function() 781 local result = exec_lua(function() 782 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 783 784 local result = {} 785 786 vim.diagnostic.config({ underline = false, virtual_text = true }) 787 788 local ns_1_diags = { 789 _G.make_error('Error 1', 1, 1, 1, 5), 790 _G.make_warning('Warning on Server 1', 2, 1, 2, 5), 791 } 792 local ns_2_diags = { 793 _G.make_warning('Warning 1', 2, 1, 2, 5), 794 } 795 796 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) 797 vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) 798 799 table.insert( 800 result, 801 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 802 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 803 ) 804 805 vim.diagnostic.enable(false, { ns_id = _G.diagnostic_ns }) 806 807 table.insert( 808 result, 809 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 810 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 811 ) 812 813 vim.diagnostic.enable(true, { ns_id = _G.diagnostic_ns }) 814 815 table.insert( 816 result, 817 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 818 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 819 ) 820 821 vim.diagnostic.enable(false, { ns_id = _G.other_ns }) 822 823 table.insert( 824 result, 825 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 826 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 827 ) 828 829 return result 830 end) 831 832 eq(3, result[1]) 833 eq(1, result[2]) 834 eq(3, result[3]) 835 eq(2, result[4]) 836 end) 837 838 --- @return table 839 local function test_enable() 840 return exec_lua(function() 841 local other_bufnr = vim.api.nvim_create_buf(true, false) 842 843 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 844 845 local result = {} 846 847 vim.diagnostic.config({ underline = false, virtual_text = true }) 848 849 local ns_1_diags = { 850 _G.make_error('Error 1', 1, 1, 1, 5), 851 _G.make_warning('Warning on Server 1', 2, 1, 2, 5), 852 } 853 local ns_2_diags = { 854 _G.make_warning('Warning 1', 2, 1, 2, 5), 855 } 856 local other_buffer_diags = { 857 _G.make_info('This is interesting', 0, 0, 0, 0), 858 } 859 860 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) 861 vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) 862 vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags) 863 864 table.insert( 865 result, 866 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 867 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 868 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 869 ) 870 871 vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) 872 873 table.insert( 874 result, 875 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 876 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 877 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 878 ) 879 880 vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.other_ns }) 881 882 table.insert( 883 result, 884 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 885 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 886 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 887 ) 888 889 vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) 890 891 table.insert( 892 result, 893 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 894 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 895 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 896 ) 897 898 -- Should have no effect 899 vim.diagnostic.enable(false, { bufnr = other_bufnr, ns_id = _G.other_ns }) 900 901 table.insert( 902 result, 903 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 904 + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) 905 + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) 906 ) 907 908 return result 909 end) 910 end 911 912 it('with both buffer and namespace arguments', function() 913 local result = test_enable() 914 eq(4, result[1]) 915 eq(2, result[2]) 916 eq(1, result[3]) 917 eq(3, result[4]) 918 eq(3, result[5]) 919 end) 920 end) 921 922 describe('reset()', function() 923 it('diagnostic count is 0 and displayed diagnostics are 0 after call', function() 924 exec_lua(function() 925 vim.diagnostic.config({ virtual_text = true }) 926 end) 927 928 -- 1 Error (1) 929 -- 1 Warning (2) 930 -- 1 Warning (2) + 1 Warning (1) 931 -- 2 highlights and 2 underlines (since error) 932 -- 1 highlight + 1 underline 933 local all_highlights = { 1, 1, 2, 4, 2 } 934 eq( 935 all_highlights, 936 exec_lua(function() 937 local ns_1_diags = { 938 _G.make_error('Error 1', 1, 1, 1, 5), 939 _G.make_warning('Warning on Server 1', 2, 1, 2, 3), 940 } 941 local ns_2_diags = { 942 _G.make_warning('Warning 1', 2, 1, 2, 3), 943 } 944 945 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) 946 vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) 947 948 return { 949 _G.count_diagnostics( 950 _G.diagnostic_bufnr, 951 vim.diagnostic.severity.ERROR, 952 _G.diagnostic_ns 953 ), 954 _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), 955 _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), 956 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), 957 _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), 958 } 959 end) 960 ) 961 962 -- Reset diagnostics from namespace 1 963 exec_lua([[ vim.diagnostic.reset( _G.diagnostic_ns) ]]) 964 965 -- Make sure we have the right diagnostic count 966 eq( 967 { 0, 1, 1, 0, 2 }, 968 exec_lua(function() 969 local diagnostic_count = {} 970 vim.wait(100, function() 971 diagnostic_count = { 972 _G.count_diagnostics( 973 _G.diagnostic_bufnr, 974 vim.diagnostic.severity.ERROR, 975 _G.diagnostic_ns 976 ), 977 _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), 978 _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), 979 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), 980 _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), 981 } 982 end) 983 return diagnostic_count 984 end) 985 ) 986 987 -- Reset diagnostics from namespace 2 988 exec_lua([[ vim.diagnostic.reset(_G.other_ns) ]]) 989 990 -- Make sure we have the right diagnostic count 991 eq( 992 { 0, 0, 0, 0, 0 }, 993 exec_lua(function() 994 local diagnostic_count = {} 995 vim.wait(100, function() 996 diagnostic_count = { 997 _G.count_diagnostics( 998 _G.diagnostic_bufnr, 999 vim.diagnostic.severity.ERROR, 1000 _G.diagnostic_ns 1001 ), 1002 _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), 1003 _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), 1004 _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), 1005 _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), 1006 } 1007 end) 1008 return diagnostic_count 1009 end) 1010 ) 1011 end) 1012 1013 it("doesn't error after bwipeout called on buffer", function() 1014 exec_lua(function() 1015 vim.diagnostic.set( 1016 _G.diagnostic_ns, 1017 _G.diagnostic_bufnr, 1018 { { message = '', lnum = 0, end_lnum = 0, col = 0, end_col = 0 } } 1019 ) 1020 vim.cmd('bwipeout! ' .. _G.diagnostic_bufnr) 1021 1022 vim.diagnostic.reset(_G.diagnostic_ns) 1023 end) 1024 end) 1025 end) 1026 1027 describe('get_next()', function() 1028 it('can find the next pos with only one namespace', function() 1029 eq( 1030 { 1, 1 }, 1031 exec_lua(function() 1032 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1033 _G.make_error('Diagnostic #1', 1, 1, 1, 1), 1034 }) 1035 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 1036 local next = vim.diagnostic.get_next() 1037 return { next.lnum, next.col } 1038 end) 1039 ) 1040 end) 1041 1042 it('can find next pos with two errors', function() 1043 eq( 1044 { 4, 4 }, 1045 exec_lua(function() 1046 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1047 _G.make_error('Diagnostic #1', 1, 1, 1, 1), 1048 _G.make_error('Diagnostic #2', 4, 4, 4, 4), 1049 }) 1050 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 1051 vim.api.nvim_win_set_cursor(0, { 3, 1 }) 1052 local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns }) 1053 return { next.lnum, next.col } 1054 end) 1055 ) 1056 end) 1057 1058 it('can cycle when position is past error', function() 1059 eq( 1060 { 1, 1 }, 1061 exec_lua(function() 1062 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1063 _G.make_error('Diagnostic #1', 1, 1, 1, 1), 1064 }) 1065 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 1066 vim.api.nvim_win_set_cursor(0, { 3, 1 }) 1067 local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns }) 1068 return { next.lnum, next.col } 1069 end) 1070 ) 1071 end) 1072 1073 it('will not cycle when wrap is off', function() 1074 eq( 1075 nil, 1076 exec_lua(function() 1077 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1078 _G.make_error('Diagnostic #1', 1, 1, 1, 1), 1079 }) 1080 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 1081 vim.api.nvim_win_set_cursor(0, { 3, 1 }) 1082 local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns, wrap = false }) 1083 return next 1084 end) 1085 ) 1086 end) 1087 1088 it('can cycle even from the last line', function() 1089 eq( 1090 { 4, 4 }, 1091 exec_lua(function() 1092 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1093 _G.make_error('Diagnostic #2', 4, 4, 4, 4), 1094 }) 1095 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 1096 vim.api.nvim_win_set_cursor(0, { vim.api.nvim_buf_line_count(0), 1 }) 1097 local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns }) 1098 return { prev.lnum, prev.col } 1099 end) 1100 ) 1101 end) 1102 1103 it('works with diagnostics past the end of the line #16349', function() 1104 eq( 1105 { 4, 0 }, 1106 exec_lua(function() 1107 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1108 _G.make_error('Diagnostic #1', 3, 9001, 3, 9001), 1109 _G.make_error('Diagnostic #2', 4, 0, 4, 0), 1110 }) 1111 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 1112 vim.api.nvim_win_set_cursor(0, { 1, 1 }) 1113 vim.diagnostic.jump({ count = 1 }) 1114 local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns }) 1115 return { next.lnum, next.col } 1116 end) 1117 ) 1118 end) 1119 1120 it('works with diagnostics before the start of the line', function() 1121 eq( 1122 { 4, 0 }, 1123 exec_lua(function() 1124 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1125 _G.make_error('Diagnostic #1', 3, 9001, 3, 9001), 1126 _G.make_error('Diagnostic #2', 4, -1, 4, -1), 1127 }) 1128 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 1129 vim.api.nvim_win_set_cursor(0, { 1, 1 }) 1130 vim.diagnostic.jump({ count = 1 }) 1131 local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns }) 1132 return { next.lnum, next.col } 1133 end) 1134 ) 1135 end) 1136 1137 it('jumps to diagnostic with highest severity', function() 1138 exec_lua(function() 1139 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1140 _G.make_info('Info', 1, 0, 1, 1), 1141 _G.make_error('Error', 2, 0, 2, 1), 1142 _G.make_warning('Warning', 3, 0, 3, 1), 1143 _G.make_error('Error', 4, 0, 4, 1), 1144 }) 1145 1146 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 1147 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 1148 end) 1149 1150 eq( 1151 { 3, 0 }, 1152 exec_lua(function() 1153 vim.diagnostic.jump({ count = 1, _highest = true }) 1154 return vim.api.nvim_win_get_cursor(0) 1155 end) 1156 ) 1157 1158 eq( 1159 { 5, 0 }, 1160 exec_lua(function() 1161 vim.diagnostic.jump({ count = 1, _highest = true }) 1162 return vim.api.nvim_win_get_cursor(0) 1163 end) 1164 ) 1165 1166 exec_lua(function() 1167 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1168 _G.make_info('Info', 1, 0, 1, 1), 1169 _G.make_hint('Hint', 2, 0, 2, 1), 1170 _G.make_warning('Warning', 3, 0, 3, 1), 1171 _G.make_hint('Hint', 4, 0, 4, 1), 1172 _G.make_warning('Warning', 5, 0, 5, 1), 1173 }) 1174 1175 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 1176 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 1177 end) 1178 1179 eq( 1180 { 4, 0 }, 1181 exec_lua(function() 1182 vim.diagnostic.jump({ count = 1, _highest = true }) 1183 return vim.api.nvim_win_get_cursor(0) 1184 end) 1185 ) 1186 1187 eq( 1188 { 6, 0 }, 1189 exec_lua(function() 1190 vim.diagnostic.jump({ count = 1, _highest = true }) 1191 return vim.api.nvim_win_get_cursor(0) 1192 end) 1193 ) 1194 end) 1195 1196 it('jumps to next diagnostic if severity is non-nil', function() 1197 exec_lua(function() 1198 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1199 _G.make_info('Info', 1, 0, 1, 1), 1200 _G.make_error('Error', 2, 0, 2, 1), 1201 _G.make_warning('Warning', 3, 0, 3, 1), 1202 _G.make_error('Error', 4, 0, 4, 1), 1203 }) 1204 1205 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 1206 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 1207 end) 1208 1209 eq( 1210 { 2, 0 }, 1211 exec_lua(function() 1212 vim.diagnostic.jump({ count = 1 }) 1213 return vim.api.nvim_win_get_cursor(0) 1214 end) 1215 ) 1216 1217 eq( 1218 { 3, 0 }, 1219 exec_lua(function() 1220 vim.diagnostic.jump({ count = 1 }) 1221 return vim.api.nvim_win_get_cursor(0) 1222 end) 1223 ) 1224 1225 eq( 1226 { 4, 0 }, 1227 exec_lua(function() 1228 vim.diagnostic.jump({ count = 1 }) 1229 return vim.api.nvim_win_get_cursor(0) 1230 end) 1231 ) 1232 end) 1233 end) 1234 1235 describe('get_prev()', function() 1236 it('can find the previous diagnostic with only one namespace', function() 1237 eq( 1238 { 1, 1 }, 1239 exec_lua(function() 1240 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1241 _G.make_error('Diagnostic #1', 1, 1, 1, 1), 1242 }) 1243 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 1244 vim.api.nvim_win_set_cursor(0, { 3, 1 }) 1245 local prev = vim.diagnostic.get_prev() 1246 return { prev.lnum, prev.col } 1247 end) 1248 ) 1249 end) 1250 1251 it('can find the previous diagnostic with two errors', function() 1252 eq( 1253 { 1, 1 }, 1254 exec_lua(function() 1255 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1256 _G.make_error('Diagnostic #1', 1, 1, 1, 1), 1257 _G.make_error('Diagnostic #2', 4, 4, 4, 4), 1258 }) 1259 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 1260 vim.api.nvim_win_set_cursor(0, { 3, 1 }) 1261 local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns }) 1262 return { prev.lnum, prev.col } 1263 end) 1264 ) 1265 end) 1266 1267 it('can cycle when position is past error', function() 1268 eq( 1269 { 4, 4 }, 1270 exec_lua(function() 1271 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1272 _G.make_error('Diagnostic #2', 4, 4, 4, 4), 1273 }) 1274 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 1275 vim.api.nvim_win_set_cursor(0, { 3, 1 }) 1276 local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns }) 1277 return { prev.lnum, prev.col } 1278 end) 1279 ) 1280 end) 1281 1282 it('respects wrap parameter', function() 1283 eq( 1284 nil, 1285 exec_lua(function() 1286 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1287 _G.make_error('Diagnostic #2', 4, 4, 4, 4), 1288 }) 1289 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 1290 vim.api.nvim_win_set_cursor(0, { 3, 1 }) 1291 local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns, wrap = false }) 1292 return prev 1293 end) 1294 ) 1295 end) 1296 1297 it('works on blank line #28397', function() 1298 eq( 1299 { 0, 2 }, 1300 exec_lua(function() 1301 local test_bufnr = vim.api.nvim_create_buf(true, false) 1302 vim.api.nvim_buf_set_lines(test_bufnr, 0, -1, false, { 1303 'first line', 1304 '', 1305 '', 1306 'end line', 1307 }) 1308 vim.diagnostic.set(_G.diagnostic_ns, test_bufnr, { 1309 _G.make_info('Diagnostic #1', 0, 2, 0, 2), 1310 _G.make_info('Diagnostic #2', 2, 0, 2, 0), 1311 _G.make_info('Diagnostic #3', 2, 0, 2, 0), 1312 }) 1313 vim.api.nvim_win_set_buf(0, test_bufnr) 1314 vim.api.nvim_win_set_cursor(0, { 3, 0 }) 1315 return vim.diagnostic.get_prev_pos { namespace = _G.diagnostic_ns } 1316 end) 1317 ) 1318 end) 1319 end) 1320 1321 describe('jump()', function() 1322 before_each(function() 1323 exec_lua(function() 1324 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1325 _G.make_error('Diagnostic #1', 0, 0, 0, 2), 1326 _G.make_error('Diagnostic #2', 1, 1, 1, 4), 1327 _G.make_warning('Diagnostic #3', 2, -1, 2, -1), 1328 _G.make_info('Diagnostic #4', 3, 0, 3, 3), 1329 }) 1330 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 1331 end) 1332 end) 1333 1334 it('can move forward', function() 1335 eq( 1336 { 2, 1 }, 1337 exec_lua(function() 1338 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 1339 vim.diagnostic.jump({ count = 1 }) 1340 return vim.api.nvim_win_get_cursor(0) 1341 end) 1342 ) 1343 1344 eq( 1345 { 4, 0 }, 1346 exec_lua(function() 1347 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 1348 vim.diagnostic.jump({ count = 3 }) 1349 return vim.api.nvim_win_get_cursor(0) 1350 end) 1351 ) 1352 1353 eq( 1354 { 4, 0 }, 1355 exec_lua(function() 1356 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 1357 vim.diagnostic.jump({ count = math.huge, wrap = false }) 1358 return vim.api.nvim_win_get_cursor(0) 1359 end) 1360 ) 1361 end) 1362 1363 it('can move backward', function() 1364 eq( 1365 { 3, 0 }, 1366 exec_lua(function() 1367 vim.api.nvim_win_set_cursor(0, { 4, 0 }) 1368 vim.diagnostic.jump({ count = -1 }) 1369 return vim.api.nvim_win_get_cursor(0) 1370 end) 1371 ) 1372 1373 eq( 1374 { 1, 0 }, 1375 exec_lua(function() 1376 vim.api.nvim_win_set_cursor(0, { 4, 0 }) 1377 vim.diagnostic.jump({ count = -3 }) 1378 return vim.api.nvim_win_get_cursor(0) 1379 end) 1380 ) 1381 1382 eq( 1383 { 1, 0 }, 1384 exec_lua(function() 1385 vim.api.nvim_win_set_cursor(0, { 4, 0 }) 1386 vim.diagnostic.jump({ count = -math.huge, wrap = false }) 1387 return vim.api.nvim_win_get_cursor(0) 1388 end) 1389 ) 1390 end) 1391 1392 it('can filter by severity', function() 1393 eq( 1394 { 3, 0 }, 1395 exec_lua(function() 1396 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 1397 vim.diagnostic.jump({ count = 1, severity = vim.diagnostic.severity.WARN }) 1398 return vim.api.nvim_win_get_cursor(0) 1399 end) 1400 ) 1401 1402 eq( 1403 { 3, 0 }, 1404 exec_lua(function() 1405 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 1406 vim.diagnostic.jump({ count = 9999, severity = vim.diagnostic.severity.WARN }) 1407 return vim.api.nvim_win_get_cursor(0) 1408 end) 1409 ) 1410 end) 1411 1412 it('can wrap', function() 1413 eq( 1414 { 1, 0 }, 1415 exec_lua(function() 1416 vim.api.nvim_win_set_cursor(0, { 4, 0 }) 1417 vim.diagnostic.jump({ count = 1, wrap = true }) 1418 return vim.api.nvim_win_get_cursor(0) 1419 end) 1420 ) 1421 1422 eq( 1423 { 4, 0 }, 1424 exec_lua(function() 1425 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 1426 vim.diagnostic.jump({ count = -1, wrap = true }) 1427 return vim.api.nvim_win_get_cursor(0) 1428 end) 1429 ) 1430 end) 1431 1432 it('supports on_jump() handler', function() 1433 exec_lua(function() 1434 _G.jumped = false 1435 1436 vim.diagnostic.jump({ 1437 count = 1, 1438 on_jump = function() 1439 _G.jumped = true 1440 end, 1441 }) 1442 end) 1443 1444 retry(nil, nil, function() 1445 eq(true, exec_lua('return _G.jumped')) 1446 end) 1447 end) 1448 1449 describe('after inserting text before diagnostic position', function() 1450 before_each(function() 1451 api.nvim_buf_set_text(0, 3, 0, 3, 0, { 'new line', 'new ' }) 1452 end) 1453 1454 it('finds next diagnostic at a logical location', function() 1455 eq( 1456 { 5, 4 }, 1457 exec_lua(function() 1458 vim.api.nvim_win_set_cursor(0, { 3, 1 }) 1459 vim.diagnostic.jump({ count = 1 }) 1460 return vim.api.nvim_win_get_cursor(0) 1461 end) 1462 ) 1463 end) 1464 1465 it('finds previous diagnostic at a logical location', function() 1466 eq( 1467 { 5, 4 }, 1468 exec_lua(function() 1469 vim.api.nvim_win_set_cursor(0, { 6, 4 }) 1470 vim.diagnostic.jump({ count = -1 }) 1471 return vim.api.nvim_win_get_cursor(0) 1472 end) 1473 ) 1474 end) 1475 end) 1476 1477 describe('if diagnostic is set after last character in line', function() 1478 before_each(function() 1479 exec_lua(function() 1480 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1481 _G.make_error('Diagnostic #1', 2, 3, 3, 4), 1482 }) 1483 end) 1484 end) 1485 1486 it('finds next diagnostic at the end of the line', function() 1487 eq( 1488 { 3, 2 }, 1489 exec_lua(function() 1490 vim.api.nvim_win_set_cursor(0, { 3, 0 }) 1491 vim.diagnostic.jump({ count = 1 }) 1492 return vim.api.nvim_win_get_cursor(0) 1493 end) 1494 ) 1495 end) 1496 1497 it('finds previous diagnostic at the end of the line', function() 1498 eq( 1499 { 3, 2 }, 1500 exec_lua(function() 1501 vim.api.nvim_win_set_cursor(0, { 4, 2 }) 1502 vim.diagnostic.jump({ count = -1 }) 1503 return vim.api.nvim_win_get_cursor(0) 1504 end) 1505 ) 1506 end) 1507 end) 1508 1509 describe('after entire text range with a diagnostic was deleted', function() 1510 before_each(function() 1511 api.nvim_buf_set_text(0, 1, 1, 1, 4, {}) 1512 end) 1513 1514 it('does not find next diagnostic inside the deleted range', function() 1515 eq( 1516 { 3, 0 }, 1517 exec_lua(function() 1518 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 1519 vim.diagnostic.jump({ count = 1 }) 1520 return vim.api.nvim_win_get_cursor(0) 1521 end) 1522 ) 1523 end) 1524 1525 it('does not find previous diagnostic inside the deleted range', function() 1526 eq( 1527 { 1, 0 }, 1528 exec_lua(function() 1529 vim.api.nvim_win_set_cursor(0, { 3, 0 }) 1530 vim.diagnostic.jump({ count = -1 }) 1531 return vim.api.nvim_win_get_cursor(0) 1532 end) 1533 ) 1534 end) 1535 end) 1536 end) 1537 1538 describe('get()', function() 1539 it('returns an empty table when no diagnostics are present', function() 1540 eq( 1541 {}, 1542 exec_lua [[return vim.diagnostic.get( _G.diagnostic_bufnr, {namespace=diagnostic_ns})]] 1543 ) 1544 end) 1545 1546 it('returns all diagnostics when no severity is supplied', function() 1547 eq( 1548 2, 1549 exec_lua(function() 1550 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1551 _G.make_error('Error 1', 1, 1, 1, 5), 1552 _G.make_warning('Warning on Server 1', 1, 1, 2, 3), 1553 }) 1554 1555 return #vim.diagnostic.get(_G.diagnostic_bufnr) 1556 end) 1557 ) 1558 end) 1559 1560 it('returns only requested diagnostics when severity range is supplied', function() 1561 eq( 1562 { 2, 3, 2 }, 1563 exec_lua(function() 1564 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1565 _G.make_error('Error 1', 1, 1, 1, 5), 1566 _G.make_warning('Warning on Server 1', 1, 1, 2, 3), 1567 _G.make_info('Ignored information', 1, 1, 2, 3), 1568 _G.make_hint("Here's a hint", 1, 1, 2, 3), 1569 }) 1570 1571 return { 1572 #vim.diagnostic.get( 1573 _G.diagnostic_bufnr, 1574 { severity = { min = vim.diagnostic.severity.WARN } } 1575 ), 1576 #vim.diagnostic.get( 1577 _G.diagnostic_bufnr, 1578 { severity = { max = vim.diagnostic.severity.WARN } } 1579 ), 1580 #vim.diagnostic.get(_G.diagnostic_bufnr, { 1581 severity = { 1582 min = vim.diagnostic.severity.INFO, 1583 max = vim.diagnostic.severity.WARN, 1584 }, 1585 }), 1586 } 1587 end) 1588 ) 1589 end) 1590 1591 it('returns only requested diagnostics when severities are supplied', function() 1592 eq( 1593 { 1, 1, 2 }, 1594 exec_lua(function() 1595 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1596 _G.make_error('Error 1', 1, 1, 1, 5), 1597 _G.make_warning('Warning on Server 1', 1, 1, 2, 3), 1598 _G.make_info('Ignored information', 1, 1, 2, 3), 1599 _G.make_hint("Here's a hint", 1, 1, 2, 3), 1600 }) 1601 1602 return { 1603 #vim.diagnostic.get( 1604 _G.diagnostic_bufnr, 1605 { severity = { vim.diagnostic.severity.WARN } } 1606 ), 1607 #vim.diagnostic.get( 1608 _G.diagnostic_bufnr, 1609 { severity = { vim.diagnostic.severity.ERROR } } 1610 ), 1611 #vim.diagnostic.get(_G.diagnostic_bufnr, { 1612 severity = { 1613 vim.diagnostic.severity.INFO, 1614 vim.diagnostic.severity.WARN, 1615 }, 1616 }), 1617 } 1618 end) 1619 ) 1620 end) 1621 1622 it('allows filtering by line', function() 1623 eq( 1624 2, 1625 exec_lua(function() 1626 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1627 _G.make_error('Error 1', 1, 1, 1, 5), 1628 _G.make_warning('Warning on Server 1', 1, 1, 2, 3), 1629 _G.make_info('Ignored information', 1, 1, 2, 3), 1630 _G.make_error('Error On Other Line', 3, 1, 3, 5), 1631 }) 1632 1633 return #vim.diagnostic.get(_G.diagnostic_bufnr, { lnum = 2 }) 1634 end) 1635 ) 1636 end) 1637 1638 it('allows filtering by enablement', function() 1639 eq( 1640 { 3, 1, 2 }, 1641 exec_lua(function() 1642 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1643 _G.make_error('Error 1', 1, 1, 1, 5), 1644 }) 1645 vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, { 1646 _G.make_error('Error 2', 1, 1, 1, 5), 1647 _G.make_error('Error 3', 3, 1, 3, 5), 1648 }) 1649 1650 vim.diagnostic.enable(false, { ns_id = _G.other_ns }) 1651 1652 return { 1653 #vim.diagnostic.get(_G.diagnostic_bufnr), 1654 #vim.diagnostic.get(_G.diagnostic_bufnr, { enabled = true }), 1655 #vim.diagnostic.get(_G.diagnostic_bufnr, { enabled = false }), 1656 } 1657 end) 1658 ) 1659 end) 1660 end) 1661 1662 describe('count', function() 1663 it('returns actually present severity counts', function() 1664 eq( 1665 exec_lua(function() 1666 return { 1667 [vim.diagnostic.severity.ERROR] = 4, 1668 [vim.diagnostic.severity.WARN] = 3, 1669 [vim.diagnostic.severity.INFO] = 2, 1670 [vim.diagnostic.severity.HINT] = 1, 1671 } 1672 end), 1673 exec_lua(function() 1674 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1675 _G.make_error('Error 1', 1, 1, 1, 2), 1676 _G.make_error('Error 2', 1, 3, 1, 4), 1677 _G.make_error('Error 3', 1, 5, 1, 6), 1678 _G.make_error('Error 4', 1, 7, 1, 8), 1679 _G.make_warning('Warning 1', 2, 1, 2, 2), 1680 _G.make_warning('Warning 2', 2, 3, 2, 4), 1681 _G.make_warning('Warning 3', 2, 5, 2, 6), 1682 _G.make_info('Info 1', 3, 1, 3, 2), 1683 _G.make_info('Info 2', 3, 3, 3, 4), 1684 _G.make_hint('Hint 1', 4, 1, 4, 2), 1685 }) 1686 return vim.diagnostic.count(_G.diagnostic_bufnr) 1687 end) 1688 ) 1689 eq( 1690 exec_lua(function() 1691 return { 1692 [vim.diagnostic.severity.ERROR] = 2, 1693 [vim.diagnostic.severity.INFO] = 1, 1694 } 1695 end), 1696 exec_lua(function() 1697 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1698 _G.make_error('Error 1', 1, 1, 1, 2), 1699 _G.make_error('Error 2', 1, 3, 1, 4), 1700 _G.make_info('Info 1', 3, 1, 3, 2), 1701 }) 1702 return vim.diagnostic.count(_G.diagnostic_bufnr) 1703 end) 1704 ) 1705 end) 1706 1707 it('returns only requested diagnostics count when severity range is supplied', function() 1708 eq( 1709 exec_lua(function() 1710 return { 1711 { [vim.diagnostic.severity.ERROR] = 1, [vim.diagnostic.severity.WARN] = 1 }, 1712 { 1713 [vim.diagnostic.severity.WARN] = 1, 1714 [vim.diagnostic.severity.INFO] = 1, 1715 [vim.diagnostic.severity.HINT] = 1, 1716 }, 1717 { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 }, 1718 } 1719 end), 1720 exec_lua(function() 1721 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1722 _G.make_error('Error 1', 1, 1, 1, 5), 1723 _G.make_warning('Warning on Server 1', 1, 1, 2, 3), 1724 _G.make_info('Ignored information', 1, 1, 2, 3), 1725 _G.make_hint("Here's a hint", 1, 1, 2, 3), 1726 }) 1727 1728 return { 1729 vim.diagnostic.count( 1730 _G.diagnostic_bufnr, 1731 { severity = { min = vim.diagnostic.severity.WARN } } 1732 ), 1733 vim.diagnostic.count( 1734 _G.diagnostic_bufnr, 1735 { severity = { max = vim.diagnostic.severity.WARN } } 1736 ), 1737 vim.diagnostic.count(_G.diagnostic_bufnr, { 1738 severity = { 1739 min = vim.diagnostic.severity.INFO, 1740 max = vim.diagnostic.severity.WARN, 1741 }, 1742 }), 1743 } 1744 end) 1745 ) 1746 end) 1747 1748 it('returns only requested diagnostics when severities are supplied', function() 1749 eq( 1750 exec_lua(function() 1751 return { 1752 { [vim.diagnostic.severity.WARN] = 1 }, 1753 { [vim.diagnostic.severity.ERROR] = 1 }, 1754 { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 }, 1755 } 1756 end), 1757 exec_lua(function() 1758 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1759 _G.make_error('Error 1', 1, 1, 1, 5), 1760 _G.make_warning('Warning on Server 1', 1, 1, 2, 3), 1761 _G.make_info('Ignored information', 1, 1, 2, 3), 1762 _G.make_hint("Here's a hint", 1, 1, 2, 3), 1763 }) 1764 1765 return { 1766 vim.diagnostic.count( 1767 _G.diagnostic_bufnr, 1768 { severity = { vim.diagnostic.severity.WARN } } 1769 ), 1770 vim.diagnostic.count( 1771 _G.diagnostic_bufnr, 1772 { severity = { vim.diagnostic.severity.ERROR } } 1773 ), 1774 vim.diagnostic.count(_G.diagnostic_bufnr, { 1775 severity = { 1776 vim.diagnostic.severity.INFO, 1777 vim.diagnostic.severity.WARN, 1778 }, 1779 }), 1780 } 1781 end) 1782 ) 1783 end) 1784 1785 it('allows filtering by line', function() 1786 eq( 1787 exec_lua(function() 1788 return { 1789 [vim.diagnostic.severity.WARN] = 1, 1790 [vim.diagnostic.severity.INFO] = 1, 1791 } 1792 end), 1793 exec_lua(function() 1794 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1795 _G.make_error('Error 1', 1, 1, 1, 5), 1796 _G.make_warning('Warning on Server 1', 1, 1, 2, 3), 1797 _G.make_info('Ignored information', 1, 1, 2, 3), 1798 _G.make_error('Error On Other Line', 3, 1, 3, 5), 1799 }) 1800 1801 return vim.diagnostic.count(_G.diagnostic_bufnr, { lnum = 2 }) 1802 end) 1803 ) 1804 end) 1805 end) 1806 1807 describe('config()', function() 1808 it('works with global, namespace, and ephemeral options', function() 1809 eq( 1810 1, 1811 exec_lua(function() 1812 vim.diagnostic.config({ 1813 virtual_text = false, 1814 }) 1815 1816 vim.diagnostic.config({ 1817 virtual_text = true, 1818 underline = false, 1819 }, _G.diagnostic_ns) 1820 1821 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1822 _G.make_error('Some Error', 4, 4, 4, 4), 1823 }) 1824 1825 return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 1826 end) 1827 ) 1828 1829 eq( 1830 1, 1831 exec_lua(function() 1832 vim.diagnostic.config({ 1833 virtual_text = false, 1834 }) 1835 1836 vim.diagnostic.config({ 1837 virtual_text = false, 1838 underline = false, 1839 }, _G.diagnostic_ns) 1840 1841 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1842 _G.make_error('Some Error', 4, 4, 4, 4), 1843 }, { virtual_text = true }) 1844 1845 return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 1846 end) 1847 ) 1848 1849 eq( 1850 0, 1851 exec_lua(function() 1852 vim.diagnostic.config({ 1853 virtual_text = false, 1854 }) 1855 1856 vim.diagnostic.config({ 1857 virtual_text = { severity = vim.diagnostic.severity.ERROR }, 1858 underline = false, 1859 }, _G.diagnostic_ns) 1860 1861 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1862 _G.make_warning('Some Warning', 4, 4, 4, 4), 1863 }, { virtual_text = true }) 1864 1865 return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 1866 end) 1867 ) 1868 1869 eq( 1870 1, 1871 exec_lua(function() 1872 vim.diagnostic.config({ 1873 virtual_text = false, 1874 }) 1875 1876 vim.diagnostic.config({ 1877 virtual_text = { severity = vim.diagnostic.severity.ERROR }, 1878 underline = false, 1879 }, _G.diagnostic_ns) 1880 1881 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1882 _G.make_warning('Some Warning', 4, 4, 4, 4), 1883 }, { 1884 virtual_text = {}, -- An empty table uses default values 1885 }) 1886 1887 return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 1888 end) 1889 ) 1890 end) 1891 1892 it('can use functions for config values', function() 1893 exec_lua(function() 1894 vim.diagnostic.config({ 1895 virtual_text = function() 1896 return true 1897 end, 1898 }, _G.diagnostic_ns) 1899 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1900 _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), 1901 }) 1902 end) 1903 1904 eq( 1905 1, 1906 exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] 1907 ) 1908 eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) 1909 1910 -- Now, don't enable virtual text. 1911 -- We should have one less extmark displayed. 1912 exec_lua(function() 1913 vim.diagnostic.config({ 1914 virtual_text = function() 1915 return false 1916 end, 1917 }, _G.diagnostic_ns) 1918 end) 1919 1920 eq( 1921 1, 1922 exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] 1923 ) 1924 eq(1, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) 1925 end) 1926 1927 it('allows filtering by severity', function() 1928 local get_extmark_count_with_severity = function(min_severity) 1929 return exec_lua(function() 1930 vim.diagnostic.config({ 1931 underline = false, 1932 virtual_text = { 1933 severity = { min = min_severity }, 1934 }, 1935 }) 1936 1937 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1938 _G.make_warning('Delayed Diagnostic', 4, 4, 4, 4), 1939 }) 1940 1941 return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 1942 end) 1943 end 1944 1945 -- No messages with Error or higher 1946 eq(0, get_extmark_count_with_severity('ERROR')) 1947 1948 -- But now we don't filter it 1949 eq(1, get_extmark_count_with_severity('WARN')) 1950 eq(1, get_extmark_count_with_severity('HINT')) 1951 end) 1952 1953 it('allows sorting by severity', function() 1954 exec_lua(function() 1955 vim.diagnostic.config({ 1956 underline = false, 1957 signs = true, 1958 virtual_text = true, 1959 }) 1960 1961 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 1962 _G.make_warning('Warning', 4, 4, 4, 4), 1963 _G.make_error('Error', 4, 4, 4, 4), 1964 _G.make_info('Info', 4, 4, 4, 4), 1965 }) 1966 1967 function _G.get_highest_underline_hl(severity_sort) 1968 vim.diagnostic.config({ 1969 underline = true, 1970 severity_sort = severity_sort, 1971 }) 1972 1973 local extmarks = _G.get_underline_extmarks(_G.diagnostic_ns) 1974 1975 table.sort(extmarks, function(a, b) 1976 return a[4].priority > b[4].priority 1977 end) 1978 1979 return extmarks[1][4].hl_group 1980 end 1981 1982 function _G.get_virt_text_and_signs(severity_sort) 1983 vim.diagnostic.config({ 1984 severity_sort = severity_sort, 1985 }) 1986 1987 local virt_text = _G.get_virt_text_extmarks(_G.diagnostic_ns)[1][4].virt_text 1988 1989 local virt_texts = {} 1990 for i = 2, #virt_text - 1 do 1991 table.insert(virt_texts, (string.gsub(virt_text[i][2], 'DiagnosticVirtualText', ''))) 1992 end 1993 1994 local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns) 1995 local sign_ns = ns.user_data.sign_ns 1996 local signs = {} 1997 local all_signs = vim.api.nvim_buf_get_extmarks( 1998 _G.diagnostic_bufnr, 1999 sign_ns, 2000 0, 2001 -1, 2002 { type = 'sign', details = true } 2003 ) 2004 table.sort(all_signs, function(a, b) 2005 return a[1] > b[1] 2006 end) 2007 2008 for _, v in ipairs(all_signs) do 2009 local s = v[4].sign_hl_group:gsub('DiagnosticSign', '') 2010 if not vim.tbl_contains(signs, s) then 2011 signs[#signs + 1] = s 2012 end 2013 end 2014 2015 return { virt_texts, signs } 2016 end 2017 end) 2018 2019 local result = exec_lua [[return _G.get_virt_text_and_signs(false)]] 2020 2021 -- Virt texts are defined lowest priority to highest, signs from 2022 -- highest to lowest 2023 eq({ 'Warn', 'Error', 'Info' }, result[1]) 2024 eq({ 'Info', 'Error', 'Warn' }, result[2]) 2025 2026 result = exec_lua [[return _G.get_virt_text_and_signs(true)]] 2027 eq({ 'Info', 'Warn', 'Error' }, result[1]) 2028 eq({ 'Error', 'Warn', 'Info' }, result[2]) 2029 2030 result = exec_lua [[return _G.get_virt_text_and_signs({ reverse = true })]] 2031 eq({ 'Error', 'Warn', 'Info' }, result[1]) 2032 eq({ 'Info', 'Warn', 'Error' }, result[2]) 2033 2034 local underline_hl = exec_lua [[return _G.get_highest_underline_hl(true)]] 2035 eq('DiagnosticUnderlineError', underline_hl) 2036 2037 underline_hl = exec_lua [[return _G.get_highest_underline_hl({ reverse = true })]] 2038 eq('DiagnosticUnderlineInfo', underline_hl) 2039 end) 2040 2041 it( 2042 'shows deprecated and unnecessary highlights in addition to severity-based highlights', 2043 function() 2044 ---@type string[] 2045 local result = exec_lua(function() 2046 local diagnostic = _G.make_error('Some error', 0, 0, 0, 0, 'source x') 2047 diagnostic._tags = { 2048 deprecated = true, 2049 unnecessary = true, 2050 } 2051 2052 local diagnostics = { diagnostic } 2053 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 2054 2055 local extmarks = _G.get_underline_extmarks(_G.diagnostic_ns) 2056 local hl_groups = vim.tbl_map(function(extmark) 2057 return extmark[4].hl_group 2058 end, extmarks) 2059 return hl_groups 2060 end) 2061 2062 eq({ 2063 'DiagnosticDeprecated', 2064 'DiagnosticUnnecessary', 2065 'DiagnosticUnderlineError', 2066 }, result) 2067 end 2068 ) 2069 2070 it('can show diagnostic sources in virtual text', function() 2071 local result = exec_lua(function() 2072 local diagnostics = { 2073 _G.make_error('Some error', 0, 0, 0, 0, 'source x'), 2074 } 2075 2076 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { 2077 underline = false, 2078 virtual_text = { 2079 prefix = '', 2080 source = 'always', 2081 }, 2082 }) 2083 2084 local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) 2085 local virt_text = extmarks[1][4].virt_text[3][1] 2086 return virt_text 2087 end) 2088 eq(' source x: Some error', result) 2089 2090 result = exec_lua(function() 2091 vim.diagnostic.config({ 2092 underline = false, 2093 virtual_text = { 2094 prefix = '', 2095 source = 'if_many', 2096 }, 2097 }, _G.diagnostic_ns) 2098 2099 local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) 2100 local virt_text = extmarks[1][4].virt_text[3][1] 2101 return virt_text 2102 end) 2103 eq(' Some error', result) 2104 2105 result = exec_lua(function() 2106 local diagnostics = { 2107 _G.make_error('Some error', 0, 0, 0, 0, 'source x'), 2108 _G.make_error('Another error', 1, 1, 1, 1, 'source y'), 2109 } 2110 2111 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { 2112 underline = false, 2113 virtual_text = { 2114 prefix = '', 2115 source = 'if_many', 2116 }, 2117 }) 2118 2119 local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) 2120 local virt_text = { extmarks[1][4].virt_text[3][1], extmarks[2][4].virt_text[3][1] } 2121 return virt_text 2122 end) 2123 eq(' source x: Some error', result[1]) 2124 eq(' source y: Another error', result[2]) 2125 end) 2126 2127 it('supports a format function for diagnostic messages', function() 2128 local result = exec_lua(function() 2129 vim.diagnostic.config({ 2130 underline = false, 2131 virtual_text = { 2132 prefix = '', 2133 format = function(diagnostic) 2134 if diagnostic.severity == vim.diagnostic.severity.ERROR then 2135 return string.format('🔥 %s', diagnostic.message) 2136 end 2137 return string.format('👀 %s', diagnostic.message) 2138 end, 2139 }, 2140 }) 2141 2142 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2143 _G.make_warning('Warning', 0, 0, 0, 0), 2144 _G.make_error('Error', 1, 0, 1, 0), 2145 }) 2146 2147 local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) 2148 return { extmarks[1][4].virt_text, extmarks[2][4].virt_text } 2149 end) 2150 eq(' 👀 Warning', result[1][3][1]) 2151 eq(' 🔥 Error', result[2][3][1]) 2152 end) 2153 2154 it('includes source for formatted diagnostics', function() 2155 local result = exec_lua(function() 2156 vim.diagnostic.config({ 2157 underline = false, 2158 virtual_text = { 2159 prefix = '', 2160 source = 'always', 2161 format = function(diagnostic) 2162 if diagnostic.severity == vim.diagnostic.severity.ERROR then 2163 return string.format('🔥 %s', diagnostic.message) 2164 end 2165 return string.format('👀 %s', diagnostic.message) 2166 end, 2167 }, 2168 }) 2169 2170 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2171 _G.make_warning('Warning', 0, 0, 0, 0, 'some_linter'), 2172 _G.make_error('Error', 1, 0, 1, 0, 'another_linter'), 2173 }) 2174 2175 local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) 2176 return { extmarks[1][4].virt_text, extmarks[2][4].virt_text } 2177 end) 2178 eq(' some_linter: 👀 Warning', result[1][3][1]) 2179 eq(' another_linter: 🔥 Error', result[2][3][1]) 2180 end) 2181 2182 it('can add a prefix to virtual text', function() 2183 eq( 2184 'E Some error', 2185 exec_lua(function() 2186 local diagnostics = { 2187 _G.make_error('Some error', 0, 0, 0, 0), 2188 } 2189 2190 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { 2191 underline = false, 2192 virtual_text = { 2193 prefix = 'E', 2194 suffix = '', 2195 }, 2196 }) 2197 2198 local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) 2199 local prefix = extmarks[1][4].virt_text[2][1] 2200 local message = extmarks[1][4].virt_text[3][1] 2201 return prefix .. message 2202 end) 2203 ) 2204 2205 eq( 2206 '[(1/1) err-code] Some error', 2207 exec_lua(function() 2208 local diagnostics = { 2209 _G.make_error('Some error', 0, 0, 0, 0, nil, 'err-code'), 2210 } 2211 2212 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { 2213 underline = false, 2214 virtual_text = { 2215 prefix = function(diag, i, total) 2216 return string.format('[(%d/%d) %s]', i, total, diag.code) 2217 end, 2218 suffix = '', 2219 }, 2220 }) 2221 2222 local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) 2223 local prefix = extmarks[1][4].virt_text[2][1] 2224 local message = extmarks[1][4].virt_text[3][1] 2225 return prefix .. message 2226 end) 2227 ) 2228 end) 2229 2230 it('can add a suffix to virtual text', function() 2231 eq( 2232 ' Some error ✘', 2233 exec_lua(function() 2234 local diagnostics = { 2235 _G.make_error('Some error', 0, 0, 0, 0), 2236 } 2237 2238 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { 2239 underline = false, 2240 virtual_text = { 2241 prefix = '', 2242 suffix = ' ✘', 2243 }, 2244 }) 2245 2246 local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) 2247 local virt_text = extmarks[1][4].virt_text[3][1] 2248 return virt_text 2249 end) 2250 ) 2251 2252 eq( 2253 ' Some error [err-code]', 2254 exec_lua(function() 2255 local diagnostics = { 2256 _G.make_error('Some error', 0, 0, 0, 0, nil, 'err-code'), 2257 } 2258 2259 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { 2260 underline = false, 2261 virtual_text = { 2262 prefix = '', 2263 suffix = function(diag) 2264 return string.format(' [%s]', diag.code) 2265 end, 2266 }, 2267 }) 2268 2269 local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) 2270 local virt_text = extmarks[1][4].virt_text[3][1] 2271 return virt_text 2272 end) 2273 ) 2274 end) 2275 2276 it('can filter diagnostics by returning nil when formatting', function() 2277 local result = exec_lua(function() 2278 vim.diagnostic.config { 2279 virtual_text = { 2280 format = function(diagnostic) 2281 if diagnostic.code == 'foo_err' then 2282 return nil 2283 end 2284 return diagnostic.message 2285 end, 2286 }, 2287 } 2288 2289 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2290 _G.make_error('An error here!', 0, 0, 0, 0, 'foo_server', 'foo_err'), 2291 _G.make_error('An error there!', 1, 1, 1, 1, 'bar_server', 'bar_err'), 2292 }) 2293 2294 local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) 2295 return extmarks 2296 end) 2297 2298 eq(1, #result) 2299 eq(' An error there!', result[1][4].virt_text[3][1]) 2300 end) 2301 2302 it('can only show virtual_text for the current line', function() 2303 local result = exec_lua(function() 2304 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 2305 2306 vim.diagnostic.config({ virtual_text = { current_line = true } }) 2307 2308 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2309 _G.make_error('Error here!', 0, 0, 0, 0, 'foo_server'), 2310 _G.make_error('Another error there!', 1, 0, 1, 0, 'foo_server'), 2311 }) 2312 2313 local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) 2314 return extmarks 2315 end) 2316 2317 eq(1, #result) 2318 eq(' Error here!', result[1][4].virt_text[3][1]) 2319 end) 2320 2321 it('can hide virtual_text for the current line', function() 2322 local result = exec_lua(function() 2323 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 2324 2325 vim.diagnostic.config({ virtual_text = { current_line = false } }) 2326 2327 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2328 _G.make_error('Error here!', 0, 0, 0, 0, 'foo_server'), 2329 _G.make_error('Another error there!', 1, 0, 1, 0, 'foo_server'), 2330 }) 2331 2332 local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) 2333 return extmarks 2334 end) 2335 2336 eq(1, #result) 2337 eq(' Another error there!', result[1][4].virt_text[3][1]) 2338 end) 2339 2340 it('only renders virtual_line diagnostics within buffer length', function() 2341 local result = exec_lua(function() 2342 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 2343 2344 vim.diagnostic.config({ virtual_text = { current_line = false } }) 2345 2346 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2347 _G.make_error('Hidden Error here!', 0, 0, 0, 0, 'foo_server'), 2348 _G.make_error('First Error here!', 1, 0, 1, 0, 'foo_server'), 2349 _G.make_error('Second Error here!', 2, 0, 2, 0, 'foo_server'), 2350 _G.make_error('First Ignored Error here!', 3, 0, 3, 0, 'foo_server'), 2351 _G.make_error('Second Ignored Error here!', 6, 0, 6, 0, 'foo_server'), 2352 _G.make_error('Third Ignored Error here!', 8, 0, 8, 0, 'foo_server'), 2353 }) 2354 2355 vim.api.nvim_buf_set_lines(_G.diagnostic_bufnr, 2, 5, false, {}) 2356 vim.api.nvim_exec_autocmds('CursorMoved', { buffer = _G.diagnostic_bufnr }) 2357 return _G.get_virt_text_extmarks(_G.diagnostic_ns) 2358 end) 2359 2360 eq(2, #result) 2361 eq(' First Error here!', result[1][4].virt_text[3][1]) 2362 eq(' Second Error here!', result[2][4].virt_text[3][1]) 2363 end) 2364 end) 2365 2366 describe('handlers.virtual_lines', function() 2367 it('includes diagnostic code and message', function() 2368 local result = exec_lua(function() 2369 vim.diagnostic.config({ virtual_lines = true }) 2370 2371 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2372 _G.make_error('Missed symbol `,`', 0, 0, 0, 0, 'lua_ls', 'miss-symbol'), 2373 }) 2374 2375 local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns) 2376 return extmarks[1][4].virt_lines 2377 end) 2378 2379 eq('miss-symbol: Missed symbol `,`', result[1][3][1]) 2380 end) 2381 2382 it('adds space to the left of the diagnostic', function() 2383 local error_offset = 5 2384 local result = exec_lua(function() 2385 vim.diagnostic.config({ virtual_lines = true }) 2386 2387 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2388 _G.make_error('Error here!', 0, error_offset, 0, error_offset, 'foo_server'), 2389 }) 2390 2391 local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns) 2392 return extmarks[1][4].virt_lines 2393 end) 2394 2395 eq(error_offset, result[1][1][1]:len()) 2396 end) 2397 2398 it('highlights diagnostics in multiple lines by default', function() 2399 local result = exec_lua(function() 2400 vim.diagnostic.config({ virtual_lines = true }) 2401 2402 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2403 _G.make_error('Error here!', 0, 0, 0, 0, 'foo_server'), 2404 _G.make_error('Another error there!', 1, 0, 1, 0, 'foo_server'), 2405 }) 2406 2407 local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns) 2408 return extmarks 2409 end) 2410 2411 eq(2, #result) 2412 eq('Error here!', result[1][4].virt_lines[1][3][1]) 2413 eq('Another error there!', result[2][4].virt_lines[1][3][1]) 2414 end) 2415 2416 it('highlights multiple diagnostics in a single line by default', function() 2417 local result = exec_lua(function() 2418 vim.api.nvim_buf_set_lines( 2419 _G.diagnostic_bufnr, 2420 0, 2421 -1, 2422 false, 2423 { 'def foo(x: int, /, y: str, *, z: float) -> None: ...' } 2424 ) 2425 2426 vim.diagnostic.config({ virtual_lines = true }) 2427 2428 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2429 _G.make_error('Error here!', 0, 8, 0, 9, 'foo_server'), 2430 _G.make_error('Another error there!', 0, 19, 0, 20, 'foo_server'), 2431 _G.make_error('And another one!', 0, 30, 0, 31, 'foo_server'), 2432 }) 2433 2434 local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns) 2435 return extmarks 2436 end) 2437 2438 --[[ 2439 |def foo(x: int, /, y: str, *, z: float) -> None: ... 2440 | │ │ └──── And another one! 2441 | │ └──── Another error there! 2442 | └──── Error here! 2443 | ^ col=8 2444 | ^ col=19 2445 | ^ col=30 2446 2447 11 cols between each diagnostic after the first one (10 spaces + |) 2448 ]] 2449 2450 eq(1, #result) 2451 local virt_lines = result[1][4].virt_lines 2452 eq(8, virt_lines[1][1][1]:len()) -- first space 2453 eq(10, virt_lines[1][3][1]:len()) -- second space 2454 eq(10, virt_lines[1][5][1]:len()) -- third space 2455 eq('And another one!', virt_lines[1][7][1]) 2456 eq(8, virt_lines[2][1][1]:len()) -- first space 2457 eq(10, virt_lines[2][3][1]:len()) -- second space 2458 eq('Another error there!', virt_lines[2][5][1]) 2459 eq(8, virt_lines[3][1][1]:len()) -- first space 2460 eq('Error here!', virt_lines[3][3][1]) 2461 end) 2462 2463 it('highlights overlapping diagnostics on a single line', function() 2464 local result = exec_lua(function() 2465 vim.diagnostic.config({ virtual_lines = true }) 2466 2467 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2468 _G.make_error('Error here!', 0, 10, 0, 11, 'foo_server'), 2469 _G.make_error('Another error here!', 0, 10, 0, 11, 'foo_server'), 2470 }) 2471 2472 local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns) 2473 return extmarks 2474 end) 2475 2476 --[[ 2477 |1234567890x 2478 | ├──── Another error here! 2479 | └──── Error here! 2480 ]] 2481 2482 eq(1, #result) 2483 local virt_lines = result[1][4].virt_lines 2484 eq(10, virt_lines[1][1][1]:len()) -- first space 2485 eq('├──── ', virt_lines[1][2][1]) 2486 eq('Another error here!', virt_lines[1][3][1]) 2487 eq(10, virt_lines[2][1][1]:len()) -- second space 2488 eq('└──── ', virt_lines[2][2][1]) 2489 eq('Error here!', virt_lines[2][3][1]) 2490 end) 2491 2492 it('handles multi-line diagnostic message', function() 2493 local result = exec_lua(function() 2494 vim.diagnostic.config({ virtual_lines = true }) 2495 2496 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2497 _G.make_error('Error here!\ngot another line', 0, 10, 0, 11, 'foo_server'), 2498 }) 2499 2500 local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns) 2501 return extmarks 2502 end) 2503 2504 --[[ 2505 |1234567890x 2506 | └──── Error here! 2507 | got another line 2508 ]] 2509 2510 eq(1, #result) 2511 local virt_lines = result[1][4].virt_lines 2512 eq(10, virt_lines[1][1][1]:len()) -- first space 2513 eq('└──── ', virt_lines[1][2][1]) 2514 eq('Error here!', virt_lines[1][3][1]) 2515 eq(10, virt_lines[2][1][1]:len()) -- second line space 2516 eq(6, virt_lines[2][2][1]:len()) -- extra padding 2517 eq('got another line', virt_lines[2][3][1]) 2518 end) 2519 2520 it('can highlight diagnostics only in the current line', function() 2521 local result = exec_lua(function() 2522 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 2523 2524 vim.diagnostic.config({ virtual_lines = { current_line = true } }) 2525 2526 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2527 _G.make_error('Error here!', 0, 0, 0, 0, 'foo_server'), 2528 _G.make_error('Another error there!', 1, 0, 1, 0, 'foo_server'), 2529 }) 2530 2531 local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns) 2532 return extmarks 2533 end) 2534 2535 eq(1, #result) 2536 eq('Error here!', result[1][4].virt_lines[1][3][1]) 2537 end) 2538 2539 it('supports a format function for diagnostic messages', function() 2540 local result = exec_lua(function() 2541 vim.diagnostic.config({ 2542 virtual_lines = { 2543 format = function() 2544 return 'Error here!' 2545 end, 2546 }, 2547 }) 2548 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2549 _G.make_error('Invalid syntax', 0, 0, 0, 0), 2550 }) 2551 local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns) 2552 return extmarks[1][4].virt_lines 2553 end) 2554 eq('Error here!', result[1][3][1]) 2555 end) 2556 2557 it('sorts by severity with stable tiebreaker #37137', function() 2558 local result = exec_lua(function() 2559 vim.diagnostic.config({ severity_sort = true, virtual_lines = { current_line = true } }) 2560 local m = 100 2561 local diagnostics = { 2562 { end_col = m, lnum = 0, message = 'a', severity = 2 }, 2563 { end_col = m, lnum = 0, message = 'b', severity = 2 }, 2564 { end_col = m, lnum = 0, message = 'c', severity = 2 }, 2565 { end_col = m, lnum = 2, message = 'd', severity = 2 }, 2566 { end_col = m, lnum = 2, message = 'e', severity = 2 }, 2567 { end_col = m, lnum = 2, message = 'f', severity = 2 }, 2568 } 2569 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, {}) 2570 vim.diagnostic.show(_G.diagnostic_ns, _G.diagnostic_bufnr) 2571 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 2572 local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns) 2573 local result = {} 2574 for _, d in ipairs(extmarks[1][4].virt_lines) do 2575 table.insert(result, d[3][1]) 2576 end 2577 return result 2578 end) 2579 eq({ 'c', 'b', 'a' }, result) 2580 end) 2581 end) 2582 2583 describe('set()', function() 2584 it('validation', function() 2585 matches( 2586 'expected a list of diagnostics', 2587 pcall_err(exec_lua, [[vim.diagnostic.set(1, 0, {lnum = 1, col = 2})]]) 2588 ) 2589 end) 2590 2591 it('can perform updates after insert_leave', function() 2592 exec_lua(function() 2593 vim.diagnostic.config({ virtual_text = true }) 2594 vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) 2595 end) 2596 2597 api.nvim_input('o') 2598 eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) 2599 2600 -- Save the diagnostics 2601 exec_lua(function() 2602 vim.diagnostic.config({ 2603 update_in_insert = false, 2604 }) 2605 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2606 _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), 2607 }) 2608 end) 2609 2610 -- No diagnostics displayed yet. 2611 eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) 2612 eq( 2613 1, 2614 exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] 2615 ) 2616 eq(0, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) 2617 2618 api.nvim_input('<esc>') 2619 eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) 2620 2621 eq( 2622 1, 2623 exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] 2624 ) 2625 eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) 2626 end) 2627 2628 it('does not perform updates when not needed', function() 2629 exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]] 2630 api.nvim_input('o') 2631 eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) 2632 2633 -- Save the diagnostics 2634 exec_lua(function() 2635 vim.diagnostic.config({ 2636 update_in_insert = false, 2637 virtual_text = true, 2638 }) 2639 2640 _G.DisplayCount = 0 2641 local set_virtual_text = vim.diagnostic.handlers.virtual_text.show 2642 vim.diagnostic.handlers.virtual_text.show = function(...) 2643 _G.DisplayCount = _G.DisplayCount + 1 2644 return set_virtual_text(...) 2645 end 2646 2647 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2648 _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), 2649 }) 2650 end) 2651 2652 -- No diagnostics displayed yet. 2653 eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) 2654 eq( 2655 1, 2656 exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] 2657 ) 2658 eq(0, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) 2659 eq(0, exec_lua [[return _G.DisplayCount]]) 2660 2661 api.nvim_input('<esc>') 2662 eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) 2663 2664 eq( 2665 1, 2666 exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] 2667 ) 2668 eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) 2669 eq(1, exec_lua [[return _G.DisplayCount]]) 2670 2671 -- Go in and out of insert mode one more time. 2672 api.nvim_input('o') 2673 eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) 2674 2675 api.nvim_input('<esc>') 2676 eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) 2677 2678 -- Should not have set the virtual text again. 2679 eq(1, exec_lua [[return _G.DisplayCount]]) 2680 end) 2681 2682 it('never sets virtual text, in combination with insert leave', function() 2683 exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]] 2684 api.nvim_input('o') 2685 eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) 2686 2687 -- Save the diagnostics 2688 exec_lua(function() 2689 vim.diagnostic.config({ 2690 update_in_insert = false, 2691 virtual_text = false, 2692 }) 2693 2694 _G.DisplayCount = 0 2695 local set_virtual_text = vim.diagnostic.handlers.virtual_text.show 2696 vim.diagnostic.handlers.virtual_text.show = function(...) 2697 _G.DisplayCount = _G.DisplayCount + 1 2698 return set_virtual_text(...) 2699 end 2700 2701 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2702 _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), 2703 }) 2704 end) 2705 2706 -- No diagnostics displayed yet. 2707 eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) 2708 eq( 2709 1, 2710 exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] 2711 ) 2712 eq(0, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) 2713 eq(0, exec_lua [[return _G.DisplayCount]]) 2714 2715 api.nvim_input('<esc>') 2716 eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) 2717 2718 eq( 2719 1, 2720 exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] 2721 ) 2722 eq(1, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) 2723 eq(0, exec_lua [[return _G.DisplayCount]]) 2724 2725 -- Go in and out of insert mode one more time. 2726 api.nvim_input('o') 2727 eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) 2728 2729 api.nvim_input('<esc>') 2730 eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) 2731 2732 -- Should not have set the virtual text still. 2733 eq(0, exec_lua [[return _G.DisplayCount]]) 2734 end) 2735 2736 it('can perform updates while in insert mode, if desired', function() 2737 exec_lua(function() 2738 vim.diagnostic.config({ virtual_text = true }) 2739 vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) 2740 end) 2741 api.nvim_input('o') 2742 eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) 2743 2744 -- Save the diagnostics 2745 exec_lua(function() 2746 vim.diagnostic.config({ 2747 update_in_insert = true, 2748 }) 2749 2750 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2751 _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), 2752 }) 2753 end) 2754 2755 -- Diagnostics are displayed, because the user wanted them that way! 2756 eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) 2757 eq( 2758 1, 2759 exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] 2760 ) 2761 eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) 2762 2763 api.nvim_input('<esc>') 2764 eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) 2765 2766 eq( 2767 1, 2768 exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] 2769 ) 2770 eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) 2771 end) 2772 2773 it('can set diagnostics without displaying them', function() 2774 exec_lua(function() 2775 vim.diagnostic.config({ virtual_text = true }) 2776 end) 2777 2778 eq( 2779 0, 2780 exec_lua(function() 2781 vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) 2782 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2783 _G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), 2784 }) 2785 return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 2786 end) 2787 ) 2788 2789 eq( 2790 2, 2791 exec_lua(function() 2792 vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) 2793 return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 2794 end) 2795 ) 2796 end) 2797 2798 it('can set display options', function() 2799 eq( 2800 0, 2801 exec_lua(function() 2802 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2803 _G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), 2804 }, { virtual_text = false, underline = false }) 2805 return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 2806 end) 2807 ) 2808 2809 eq( 2810 1, 2811 exec_lua(function() 2812 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 2813 _G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), 2814 }, { virtual_text = true, underline = false }) 2815 return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) 2816 end) 2817 ) 2818 end) 2819 2820 it('sets and clears signs #26193 #26555', function() 2821 do 2822 local result = exec_lua(function() 2823 vim.diagnostic.config({ 2824 signs = true, 2825 }) 2826 2827 local diagnostics = { 2828 _G.make_error('Error', 1, 1, 1, 2), 2829 _G.make_warning('Warning', 3, 3, 3, 3), 2830 } 2831 2832 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 2833 2834 local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns) 2835 local sign_ns = ns.user_data.sign_ns 2836 2837 local signs = vim.api.nvim_buf_get_extmarks( 2838 _G.diagnostic_bufnr, 2839 sign_ns, 2840 0, 2841 -1, 2842 { type = 'sign', details = true } 2843 ) 2844 local result = {} 2845 for _, s in ipairs(signs) do 2846 result[#result + 1] = { lnum = s[2] + 1, name = s[4].sign_hl_group } 2847 end 2848 return result 2849 end) 2850 2851 eq({ 2, 'DiagnosticSignError' }, { result[1].lnum, result[1].name }) 2852 eq({ 4, 'DiagnosticSignWarn' }, { result[2].lnum, result[2].name }) 2853 end 2854 2855 do 2856 local result = exec_lua(function() 2857 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {}) 2858 2859 local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns) 2860 local sign_ns = ns.user_data.sign_ns 2861 2862 return vim.api.nvim_buf_get_extmarks( 2863 _G.diagnostic_bufnr, 2864 sign_ns, 2865 0, 2866 -1, 2867 { type = 'sign', details = true } 2868 ) 2869 end) 2870 2871 eq({}, result) 2872 end 2873 end) 2874 2875 it('always passes a table to DiagnosticChanged autocommand', function() 2876 local result = exec_lua(function() 2877 local changed_diags --- @type vim.Diagnostic[]? 2878 vim.api.nvim_create_autocmd('DiagnosticChanged', { 2879 buffer = _G.diagnostic_bufnr, 2880 callback = function(args) 2881 --- @type vim.Diagnostic[] 2882 changed_diags = args.data.diagnostics 2883 end, 2884 }) 2885 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {}) 2886 return changed_diags 2887 end) 2888 eq('table', type(result)) 2889 eq(0, #result) 2890 end) 2891 end) 2892 2893 describe('open_float()', function() 2894 it('can display a header', function() 2895 eq( 2896 { 'Diagnostics:', '1. Syntax error' }, 2897 exec_lua(function() 2898 local diagnostics = { 2899 _G.make_error('Syntax error', 0, 1, 0, 3), 2900 } 2901 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 2902 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 2903 local float_bufnr, winnr = vim.diagnostic.open_float() 2904 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 2905 vim.api.nvim_win_close(winnr, true) 2906 return lines 2907 end) 2908 ) 2909 2910 eq( 2911 { "We're no strangers to love...", '1. Syntax error' }, 2912 exec_lua(function() 2913 local diagnostics = { 2914 _G.make_error('Syntax error', 0, 1, 0, 3), 2915 } 2916 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 2917 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 2918 local float_bufnr, winnr = 2919 vim.diagnostic.open_float({ header = "We're no strangers to love..." }) 2920 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 2921 vim.api.nvim_win_close(winnr, true) 2922 return lines 2923 end) 2924 ) 2925 2926 eq( 2927 { 'You know the rules', '1. Syntax error' }, 2928 exec_lua(function() 2929 local diagnostics = { 2930 _G.make_error('Syntax error', 0, 1, 0, 3), 2931 } 2932 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 2933 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 2934 local float_bufnr, winnr = 2935 vim.diagnostic.open_float({ header = { 'You know the rules', 'Search' } }) 2936 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 2937 vim.api.nvim_win_close(winnr, true) 2938 return lines 2939 end) 2940 ) 2941 end) 2942 2943 it('can show diagnostics from the whole buffer', function() 2944 eq( 2945 { '1. Syntax error', '2. Some warning' }, 2946 exec_lua(function() 2947 local diagnostics = { 2948 _G.make_error('Syntax error', 0, 1, 0, 3), 2949 _G.make_warning('Some warning', 1, 1, 1, 3), 2950 } 2951 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 2952 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 2953 local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'buffer' }) 2954 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 2955 vim.api.nvim_win_close(winnr, true) 2956 return lines 2957 end) 2958 ) 2959 end) 2960 2961 it('can show diagnostics from a single line', function() 2962 -- Using cursor position 2963 eq( 2964 { '1. Some warning' }, 2965 exec_lua(function() 2966 local diagnostics = { 2967 _G.make_error('Syntax error', 0, 1, 0, 3), 2968 _G.make_warning('Some warning', 1, 1, 1, 3), 2969 } 2970 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 2971 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 2972 vim.api.nvim_win_set_cursor(0, { 2, 1 }) 2973 local float_bufnr, winnr = vim.diagnostic.open_float({ header = false }) 2974 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 2975 vim.api.nvim_win_close(winnr, true) 2976 return lines 2977 end) 2978 ) 2979 2980 -- With specified position 2981 eq( 2982 { '1. Some warning' }, 2983 exec_lua(function() 2984 local diagnostics = { 2985 _G.make_error('Syntax error', 0, 1, 0, 3), 2986 _G.make_warning('Some warning', 1, 1, 1, 3), 2987 } 2988 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 2989 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 2990 vim.api.nvim_win_set_cursor(0, { 1, 1 }) 2991 local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, pos = 1 }) 2992 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 2993 vim.api.nvim_win_close(winnr, true) 2994 return lines 2995 end) 2996 ) 2997 2998 -- End position is exclusive 2999 eq( 3000 nil, 3001 exec_lua(function() 3002 local diagnostics = { 3003 _G.make_error('Syntax error', 1, 1, 2, 0), 3004 } 3005 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3006 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3007 vim.api.nvim_win_set_cursor(0, { 1, 1 }) 3008 local _, winnr = vim.diagnostic.open_float(0, { header = false, pos = { 2, 0 } }) 3009 return winnr 3010 end) 3011 ) 3012 3013 -- Works when width == 0 3014 eq( 3015 { '1. Syntax error' }, 3016 exec_lua(function() 3017 local diagnostics = { 3018 _G.make_error('Syntax error', 2, 0, 2, 0), 3019 } 3020 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3021 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3022 vim.api.nvim_win_set_cursor(0, { 1, 1 }) 3023 local float_bufnr, winnr = 3024 vim.diagnostic.open_float(0, { header = false, pos = { 2, 1 } }) 3025 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3026 vim.api.nvim_win_close(winnr, true) 3027 return lines 3028 end) 3029 ) 3030 end) 3031 3032 it('can show diagnostics from a specific position', function() 3033 -- Using cursor position 3034 eq( 3035 { 'Syntax error' }, 3036 exec_lua(function() 3037 local diagnostics = { 3038 _G.make_error('Syntax error', 1, 1, 1, 3), 3039 _G.make_warning('Some warning', 1, 3, 1, 4), 3040 } 3041 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3042 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3043 vim.api.nvim_win_set_cursor(0, { 2, 2 }) 3044 local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'cursor' }) 3045 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3046 vim.api.nvim_win_close(winnr, true) 3047 return lines 3048 end) 3049 ) 3050 3051 -- With specified position 3052 eq( 3053 { 'Some warning' }, 3054 exec_lua(function() 3055 local diagnostics = { 3056 _G.make_error('Syntax error', 1, 1, 1, 3), 3057 _G.make_warning('Some warning', 1, 3, 1, 4), 3058 } 3059 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3060 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3061 vim.api.nvim_win_set_cursor(0, { 1, 1 }) 3062 local float_bufnr, winnr = 3063 vim.diagnostic.open_float({ header = false, scope = 'cursor', pos = { 1, 3 } }) 3064 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3065 vim.api.nvim_win_close(winnr, true) 3066 return lines 3067 end) 3068 ) 3069 3070 -- With column position past the end of the line. #16062 3071 eq( 3072 { 'Syntax error' }, 3073 exec_lua(function() 3074 local first_line_len = #vim.api.nvim_buf_get_lines(_G.diagnostic_bufnr, 0, 1, true)[1] 3075 local diagnostics = { 3076 _G.make_error('Syntax error', 0, first_line_len + 1, 1, 0), 3077 } 3078 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3079 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3080 vim.api.nvim_win_set_cursor(0, { 1, 1 }) 3081 local float_bufnr, winnr = vim.diagnostic.open_float({ 3082 header = false, 3083 scope = 'cursor', 3084 pos = { 0, first_line_len - 1 }, 3085 }) 3086 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3087 vim.api.nvim_win_close(winnr, true) 3088 return lines 3089 end) 3090 ) 3091 3092 -- End position is exclusive 3093 eq( 3094 nil, 3095 exec_lua(function() 3096 local diagnostics = { 3097 _G.make_error('Syntax error', 1, 1, 1, 3), 3098 } 3099 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3100 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3101 vim.api.nvim_win_set_cursor(0, { 1, 1 }) 3102 local _, winnr = 3103 vim.diagnostic.open_float(0, { header = false, scope = 'cursor', pos = { 1, 3 } }) 3104 return winnr 3105 end) 3106 ) 3107 3108 -- Works when width == 0 3109 eq( 3110 { 'Syntax error' }, 3111 exec_lua(function() 3112 local diagnostics = { 3113 _G.make_error('Syntax error', 2, 0, 2, 0), 3114 } 3115 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3116 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3117 vim.api.nvim_win_set_cursor(0, { 1, 1 }) 3118 local float_bufnr, winnr = 3119 vim.diagnostic.open_float({ header = false, scope = 'cursor', pos = { 2, 0 } }) 3120 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3121 vim.api.nvim_win_close(winnr, true) 3122 return lines 3123 end) 3124 ) 3125 end) 3126 3127 it( 3128 'creates floating window and returns float bufnr and winnr if current line contains diagnostics', 3129 function() 3130 -- Two lines: 3131 -- Diagnostic: 3132 -- 1. <msg> 3133 eq( 3134 2, 3135 exec_lua(function() 3136 local diagnostics = { 3137 _G.make_error('Syntax error', 0, 1, 0, 3), 3138 } 3139 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3140 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3141 local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr) 3142 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3143 vim.api.nvim_win_close(winnr, true) 3144 return #lines 3145 end) 3146 ) 3147 end 3148 ) 3149 3150 it('only reports diagnostics from the current buffer when bufnr is omitted #15710', function() 3151 eq( 3152 2, 3153 exec_lua(function() 3154 local other_bufnr = vim.api.nvim_create_buf(true, false) 3155 local buf_1_diagnostics = { 3156 _G.make_error('Syntax error', 0, 1, 0, 3), 3157 } 3158 local buf_2_diagnostics = { 3159 _G.make_warning('Some warning', 0, 1, 0, 3), 3160 } 3161 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3162 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, buf_1_diagnostics) 3163 vim.diagnostic.set(_G.other_ns, other_bufnr, buf_2_diagnostics) 3164 local float_bufnr, winnr = vim.diagnostic.open_float() 3165 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3166 vim.api.nvim_win_close(winnr, true) 3167 return #lines 3168 end) 3169 ) 3170 end) 3171 3172 it('allows filtering by namespace', function() 3173 eq( 3174 { 'Diagnostics:', '1. Syntax error' }, 3175 exec_lua(function() 3176 local ns_1_diagnostics = { 3177 _G.make_error('Syntax error', 0, 1, 0, 3), 3178 } 3179 local ns_2_diagnostics = { 3180 _G.make_warning('Some warning', 0, 1, 0, 3), 3181 } 3182 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3183 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diagnostics) 3184 vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diagnostics) 3185 local float_bufnr, winnr = 3186 vim.diagnostic.open_float(_G.diagnostic_bufnr, { namespace = _G.diagnostic_ns }) 3187 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3188 vim.api.nvim_win_close(winnr, true) 3189 return lines 3190 end) 3191 ) 3192 end) 3193 3194 it('allows filtering by multiple namespaces', function() 3195 eq( 3196 { 'Diagnostics:', '1. Syntax error', '2. Some warning' }, 3197 exec_lua(function() 3198 local ns_1_diagnostics = { 3199 _G.make_error('Syntax error', 0, 1, 0, 3), 3200 } 3201 local ns_2_diagnostics = { 3202 _G.make_warning('Some warning', 0, 1, 0, 3), 3203 } 3204 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3205 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diagnostics) 3206 vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diagnostics) 3207 local float_bufnr, winnr = vim.diagnostic.open_float( 3208 _G.diagnostic_bufnr, 3209 { namespace = { _G.diagnostic_ns, _G.other_ns } } 3210 ) 3211 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3212 vim.api.nvim_win_close(winnr, true) 3213 return lines 3214 end) 3215 ) 3216 end) 3217 3218 it( 3219 'creates floating window and returns float bufnr and winnr without header, if requested', 3220 function() 3221 -- One line (since no header): 3222 -- 1. <msg> 3223 eq( 3224 1, 3225 exec_lua(function() 3226 local diagnostics = { 3227 _G.make_error('Syntax error', 0, 1, 0, 3), 3228 } 3229 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3230 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3231 local float_bufnr, winnr = 3232 vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) 3233 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3234 vim.api.nvim_win_close(winnr, true) 3235 return #lines 3236 end) 3237 ) 3238 end 3239 ) 3240 3241 it('clamps diagnostic line numbers within the valid range', function() 3242 eq( 3243 1, 3244 exec_lua(function() 3245 local diagnostics = { 3246 _G.make_error('Syntax error', 6, 0, 6, 0), 3247 } 3248 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3249 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3250 local float_bufnr, winnr = 3251 vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false, pos = 5 }) 3252 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3253 vim.api.nvim_win_close(winnr, true) 3254 return #lines 3255 end) 3256 ) 3257 end) 3258 3259 it('can show diagnostic source', function() 3260 exec_lua [[vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)]] 3261 3262 eq( 3263 { '1. Syntax error' }, 3264 exec_lua(function() 3265 local diagnostics = { 3266 _G.make_error('Syntax error', 0, 1, 0, 3, 'source x'), 3267 } 3268 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3269 local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr, { 3270 header = false, 3271 source = 'if_many', 3272 }) 3273 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3274 vim.api.nvim_win_close(winnr, true) 3275 return lines 3276 end) 3277 ) 3278 3279 eq( 3280 { '1. source x: Syntax error' }, 3281 exec_lua(function() 3282 local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr, { 3283 header = false, 3284 source = 'always', 3285 }) 3286 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3287 vim.api.nvim_win_close(winnr, true) 3288 return lines 3289 end) 3290 ) 3291 3292 eq( 3293 { '1. source x: Syntax error', '2. source y: Another error' }, 3294 exec_lua(function() 3295 local diagnostics = { 3296 _G.make_error('Syntax error', 0, 1, 0, 3, 'source x'), 3297 _G.make_error('Another error', 0, 1, 0, 3, 'source y'), 3298 } 3299 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3300 local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr, { 3301 header = false, 3302 source = 'if_many', 3303 }) 3304 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3305 vim.api.nvim_win_close(winnr, true) 3306 return lines 3307 end) 3308 ) 3309 end) 3310 3311 it('respects severity_sort', function() 3312 exec_lua [[vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)]] 3313 3314 eq( 3315 { '1. Syntax error', '2. Info', '3. Error', '4. Warning' }, 3316 exec_lua(function() 3317 local diagnostics = { 3318 _G.make_error('Syntax error', 0, 1, 0, 3), 3319 _G.make_info('Info', 0, 3, 0, 4), 3320 _G.make_error('Error', 0, 2, 0, 2), 3321 _G.make_warning('Warning', 0, 0, 0, 1), 3322 } 3323 3324 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3325 3326 vim.diagnostic.config({ severity_sort = false }) 3327 3328 local float_bufnr, winnr = 3329 vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) 3330 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3331 vim.api.nvim_win_close(winnr, true) 3332 return lines 3333 end) 3334 ) 3335 3336 eq( 3337 { '1. Syntax error', '2. Error', '3. Warning', '4. Info' }, 3338 exec_lua(function() 3339 vim.diagnostic.config({ severity_sort = true }) 3340 local float_bufnr, winnr = 3341 vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) 3342 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3343 vim.api.nvim_win_close(winnr, true) 3344 return lines 3345 end) 3346 ) 3347 3348 eq( 3349 { '1. Info', '2. Warning', '3. Error', '4. Syntax error' }, 3350 exec_lua(function() 3351 vim.diagnostic.config({ severity_sort = { reverse = true } }) 3352 local float_bufnr, winnr = 3353 vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) 3354 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3355 vim.api.nvim_win_close(winnr, true) 3356 return lines 3357 end) 3358 ) 3359 end) 3360 3361 it('can filter by severity', function() 3362 local count_diagnostics_with_severity = function(min_severity, max_severity) 3363 return exec_lua(function() 3364 vim.diagnostic.config({ 3365 float = { 3366 severity = { min = min_severity, max = max_severity }, 3367 }, 3368 }) 3369 3370 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 3371 _G.make_error('Syntax error', 0, 1, 0, 3), 3372 _G.make_info('Info', 0, 3, 0, 4), 3373 _G.make_error('Error', 0, 2, 0, 2), 3374 _G.make_warning('Warning', 0, 0, 0, 1), 3375 }) 3376 3377 local float_bufnr, winnr = 3378 vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) 3379 if not float_bufnr then 3380 return 0 3381 end 3382 3383 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3384 vim.api.nvim_win_close(winnr, true) 3385 return #lines 3386 end) 3387 end 3388 3389 eq(2, count_diagnostics_with_severity('ERROR')) 3390 eq(3, count_diagnostics_with_severity('WARN')) 3391 eq(1, count_diagnostics_with_severity('WARN', 'WARN')) 3392 eq(4, count_diagnostics_with_severity('HINT')) 3393 eq(0, count_diagnostics_with_severity('HINT', 'HINT')) 3394 end) 3395 3396 it('can add a prefix to diagnostics', function() 3397 -- Default is to add a number 3398 eq( 3399 { '1. Syntax error', '2. Some warning' }, 3400 exec_lua(function() 3401 local diagnostics = { 3402 _G.make_error('Syntax error', 0, 1, 0, 3), 3403 _G.make_warning('Some warning', 1, 1, 1, 3), 3404 } 3405 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3406 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3407 local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'buffer' }) 3408 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3409 vim.api.nvim_win_close(winnr, true) 3410 return lines 3411 end) 3412 ) 3413 3414 eq( 3415 { 'Syntax error', 'Some warning' }, 3416 exec_lua(function() 3417 local diagnostics = { 3418 _G.make_error('Syntax error', 0, 1, 0, 3), 3419 _G.make_warning('Some warning', 1, 1, 1, 3), 3420 } 3421 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3422 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3423 local float_bufnr, winnr = 3424 vim.diagnostic.open_float({ header = false, scope = 'buffer', prefix = '' }) 3425 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3426 vim.api.nvim_win_close(winnr, true) 3427 return lines 3428 end) 3429 ) 3430 3431 eq( 3432 { '1. Syntax error', '2. Some warning' }, 3433 exec_lua(function() 3434 local diagnostics = { 3435 _G.make_error('Syntax error', 0, 1, 0, 3), 3436 _G.make_warning('Some warning', 0, 1, 0, 3), 3437 } 3438 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3439 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3440 local float_bufnr, winnr = vim.diagnostic.open_float({ 3441 header = false, 3442 prefix = function(_, i, total) 3443 -- Only show a number if there is more than one diagnostic 3444 if total > 1 then 3445 return string.format('%d. ', i) 3446 end 3447 return '' 3448 end, 3449 }) 3450 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3451 vim.api.nvim_win_close(winnr, true) 3452 return lines 3453 end) 3454 ) 3455 3456 eq( 3457 { 'Syntax error' }, 3458 exec_lua(function() 3459 local diagnostics = { 3460 _G.make_error('Syntax error', 0, 1, 0, 3), 3461 } 3462 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3463 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3464 local float_bufnr, winnr = vim.diagnostic.open_float({ 3465 header = false, 3466 prefix = function(_, i, total) 3467 -- Only show a number if there is more than one diagnostic 3468 if total > 1 then 3469 return string.format('%d. ', i) 3470 end 3471 return '' 3472 end, 3473 }) 3474 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3475 vim.api.nvim_win_close(winnr, true) 3476 return lines 3477 end) 3478 ) 3479 3480 eq( 3481 '.../diagnostic.lua:0: prefix: expected string|table|function, got number', 3482 pcall_err(exec_lua, [[ vim.diagnostic.open_float({ prefix = 42 }) ]]) 3483 ) 3484 end) 3485 3486 it('can add a suffix to diagnostics', function() 3487 -- Default is to render the diagnostic error code 3488 eq( 3489 { '1. Syntax error [code-x]', '2. Some warning [code-y]' }, 3490 exec_lua(function() 3491 local diagnostics = { 3492 _G.make_error('Syntax error', 0, 1, 0, 3, nil, 'code-x'), 3493 _G.make_warning('Some warning', 1, 1, 1, 3, nil, 'code-y'), 3494 } 3495 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3496 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3497 local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'buffer' }) 3498 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3499 vim.api.nvim_win_close(winnr, true) 3500 return lines 3501 end) 3502 ) 3503 3504 eq( 3505 { '1. Syntax error', '2. Some warning' }, 3506 exec_lua(function() 3507 local diagnostics = { 3508 _G.make_error('Syntax error', 0, 1, 0, 3, nil, 'code-x'), 3509 _G.make_warning('Some warning', 1, 1, 1, 3, nil, 'code-y'), 3510 } 3511 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3512 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3513 local float_bufnr, winnr = 3514 vim.diagnostic.open_float({ header = false, scope = 'buffer', suffix = '' }) 3515 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3516 vim.api.nvim_win_close(winnr, true) 3517 return lines 3518 end) 3519 ) 3520 3521 -- Suffix is rendered on the last line of a multiline diagnostic 3522 eq( 3523 { '1. Syntax error', ' More context [code-x]' }, 3524 exec_lua(function() 3525 local diagnostics = { 3526 _G.make_error('Syntax error\nMore context', 0, 1, 0, 3, nil, 'code-x'), 3527 } 3528 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3529 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3530 local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'buffer' }) 3531 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3532 vim.api.nvim_win_close(winnr, true) 3533 return lines 3534 end) 3535 ) 3536 3537 eq( 3538 '.../diagnostic.lua:0: suffix: expected string|table|function, got number', 3539 pcall_err(exec_lua, [[ vim.diagnostic.open_float({ suffix = 42 }) ]]) 3540 ) 3541 end) 3542 3543 it('can add LSP related information to a diagnostic', function() 3544 local related_info_uri = 'file:///fake/uri' 3545 3546 -- Populate the related info buffer. 3547 exec_lua(function() 3548 local fake_bufnr = vim.uri_to_bufnr(related_info_uri) 3549 vim.fn.bufload(fake_bufnr) 3550 vim.api.nvim_buf_set_lines(fake_bufnr, 0, 1, false, { 3551 'O, the Pelican,', 3552 'so smoothly doth he crest.', 3553 'a wind god!', 3554 }) 3555 vim.api.nvim_win_set_buf(0, fake_bufnr) 3556 end) 3557 3558 -- Displays related info. 3559 eq( 3560 { 3561 '1. Some warning', 3562 ' uri:2:1: Some extra info', 3563 ' uri:3:4: Some more extra info', 3564 }, 3565 exec_lua(function() 3566 ---@type vim.Diagnostic 3567 local diagnostic = _G.make_warning('Some warning', 1, 1, 1, 3) 3568 diagnostic.user_data = { 3569 -- Related information comes from LSP user_data 3570 lsp = { 3571 relatedInformation = { 3572 { 3573 message = 'Some extra info', 3574 location = { 3575 uri = related_info_uri, 3576 range = { 3577 start = { 3578 line = 1, 3579 character = 0, 3580 }, 3581 ['end'] = { 3582 line = 1, 3583 character = 1, 3584 }, 3585 }, 3586 }, 3587 }, 3588 { 3589 message = 'Some more extra info', 3590 location = { 3591 uri = related_info_uri, 3592 range = { 3593 start = { 3594 line = 2, 3595 character = 3, 3596 }, 3597 ['end'] = { 3598 line = 4, 3599 character = 5, 3600 }, 3601 }, 3602 }, 3603 }, 3604 }, 3605 }, 3606 } 3607 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3608 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { diagnostic }) 3609 local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'buffer' }) 3610 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3611 -- Put the cursor on a line with related info 3612 vim.api.nvim_tabpage_set_win(0, winnr) 3613 vim.api.nvim_win_set_cursor(0, { 2, 0 }) 3614 return lines 3615 end) 3616 ) 3617 3618 -- Jumps to related info. 3619 eq( 3620 'so smoothly doth he crest.', 3621 exec_lua(function() 3622 vim.cmd.norm('gf') 3623 vim.wait(20, function() end) 3624 return vim.api.nvim_get_current_line() 3625 end) 3626 ) 3627 end) 3628 3629 it('works with the old signature', function() 3630 eq( 3631 { '1. Syntax error' }, 3632 exec_lua(function() 3633 local diagnostics = { 3634 _G.make_error('Syntax error', 0, 1, 0, 3), 3635 } 3636 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3637 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3638 local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) 3639 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3640 vim.api.nvim_win_close(winnr, true) 3641 return lines 3642 end) 3643 ) 3644 end) 3645 3646 it('works for multi-line diagnostics #21949', function() 3647 -- create diagnostic 3648 exec_lua(function() 3649 local diagnostics = { 3650 _G.make_error('Error in two lines lnum is 1 and end_lnum is 2', 1, 1, 2, 3), 3651 } 3652 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3653 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) 3654 end) 3655 3656 -- open float failed non diagnostic lnum 3657 eq( 3658 nil, 3659 exec_lua(function() 3660 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 3661 local _, winnr = vim.diagnostic.open_float(0, { header = false }) 3662 return winnr 3663 end) 3664 ) 3665 eq( 3666 nil, 3667 exec_lua(function() 3668 vim.api.nvim_win_set_cursor(0, { 1, 0 }) 3669 local _, winnr = vim.diagnostic.open_float(0, { header = false, scope = 'cursor' }) 3670 return winnr 3671 end) 3672 ) 3673 3674 -- can open a float window on lnum 1 3675 eq( 3676 { '1. Error in two lines lnum is 1 and end_lnum is 2' }, 3677 exec_lua(function() 3678 vim.api.nvim_win_set_cursor(0, { 2, 0 }) 3679 local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) 3680 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3681 vim.api.nvim_win_close(winnr, true) 3682 return lines 3683 end) 3684 ) 3685 3686 -- can open a cursor-scoped float window on lnum 1 3687 eq( 3688 { 'Error in two lines lnum is 1 and end_lnum is 2' }, 3689 exec_lua(function() 3690 vim.api.nvim_win_set_cursor(0, { 2, 1 }) 3691 local float_bufnr, winnr = 3692 vim.diagnostic.open_float(0, { header = false, scope = 'cursor' }) 3693 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3694 vim.api.nvim_win_close(winnr, true) 3695 return lines 3696 end) 3697 ) 3698 3699 -- can open a float window on end_lnum 2 3700 eq( 3701 { '1. Error in two lines lnum is 1 and end_lnum is 2' }, 3702 exec_lua(function() 3703 vim.api.nvim_win_set_cursor(0, { 3, 0 }) 3704 local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) 3705 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3706 vim.api.nvim_win_close(winnr, true) 3707 return lines 3708 end) 3709 ) 3710 3711 -- can open a cursor-scoped float window on end_lnum 2 3712 eq( 3713 { 'Error in two lines lnum is 1 and end_lnum is 2' }, 3714 exec_lua(function() 3715 vim.api.nvim_win_set_cursor(0, { 3, 2 }) 3716 local float_bufnr, winnr = 3717 vim.diagnostic.open_float(0, { header = false, scope = 'cursor' }) 3718 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3719 vim.api.nvim_win_close(winnr, true) 3720 return lines 3721 end) 3722 ) 3723 end) 3724 3725 it('shows diagnostics at their logical locations after text changes before', function() 3726 exec_lua(function() 3727 vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) 3728 3729 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 3730 _G.make_error('Diagnostic #1', 1, 4, 1, 7), 3731 _G.make_error('Diagnostic #2', 3, 0, 3, 3), 3732 }) 3733 end) 3734 3735 api.nvim_buf_set_text(0, 3, 0, 3, 0, { 'new line', 'new ' }) 3736 3737 eq( 3738 { 'Diagnostic #1' }, 3739 exec_lua(function() 3740 vim.api.nvim_win_set_cursor(0, { 2, 4 }) 3741 local float_bufnr, winnr = vim.diagnostic.open_float({ header = '', scope = 'cursor' }) 3742 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3743 vim.api.nvim_win_close(winnr, true) 3744 return lines 3745 end) 3746 ) 3747 3748 eq( 3749 { 'Diagnostic #2' }, 3750 exec_lua(function() 3751 vim.api.nvim_win_set_cursor(0, { 5, 4 }) 3752 local float_bufnr, winnr = vim.diagnostic.open_float({ header = '', scope = 'cursor' }) 3753 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3754 vim.api.nvim_win_close(winnr, true) 3755 return lines 3756 end) 3757 ) 3758 end) 3759 3760 it('shows diagnostics at their logical locations after text changes inside', function() 3761 exec_lua(function() 3762 vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) 3763 3764 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 3765 _G.make_error('Diagnostic #1', 1, 0, 1, 7), 3766 }) 3767 end) 3768 3769 api.nvim_buf_set_text(0, 1, 4, 1, 4, { 'new ' }) 3770 3771 eq( 3772 { 'Diagnostic #1' }, 3773 exec_lua(function() 3774 vim.api.nvim_win_set_cursor(0, { 2, 10 }) 3775 local float_bufnr, winnr = vim.diagnostic.open_float({ header = '', scope = 'cursor' }) 3776 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3777 vim.api.nvim_win_close(winnr, true) 3778 return lines 3779 end) 3780 ) 3781 end) 3782 3783 it( 3784 'shows diagnostics at the end of the line if diagnostic is set after last character in line', 3785 function() 3786 exec_lua(function() 3787 vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) 3788 3789 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 3790 _G.make_error('Diagnostic #1', 2, 3, 3, 4), 3791 }) 3792 end) 3793 3794 eq( 3795 { 'Diagnostic #1' }, 3796 exec_lua(function() 3797 vim.api.nvim_win_set_cursor(0, { 3, 2 }) 3798 local float_bufnr, winnr = vim.diagnostic.open_float({ header = '', scope = 'cursor' }) 3799 local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) 3800 vim.api.nvim_win_close(winnr, true) 3801 return lines 3802 end) 3803 ) 3804 end 3805 ) 3806 end) 3807 3808 describe('setloclist()', function() 3809 it('sets diagnostics in lnum order', function() 3810 local loc_list = exec_lua(function() 3811 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3812 3813 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 3814 _G.make_error('Farther Diagnostic', 4, 4, 4, 4), 3815 _G.make_error('Lower Diagnostic', 1, 1, 1, 1), 3816 }) 3817 3818 vim.diagnostic.setloclist() 3819 3820 return vim.fn.getloclist(0) 3821 end) 3822 3823 assert(loc_list[1].lnum < loc_list[2].lnum) 3824 end) 3825 3826 it('sets diagnostics in lnum order, regardless of namespace', function() 3827 local loc_list = exec_lua(function() 3828 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3829 3830 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 3831 _G.make_error('Lower Diagnostic', 1, 1, 1, 1), 3832 }) 3833 3834 vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, { 3835 _G.make_warning('Farther Diagnostic', 4, 4, 4, 4), 3836 }) 3837 3838 vim.diagnostic.setloclist() 3839 3840 return vim.fn.getloclist(0) 3841 end) 3842 3843 assert(loc_list[1].lnum < loc_list[2].lnum) 3844 end) 3845 3846 it('sets diagnostics from the specified namespaces', function() 3847 local loc_list = exec_lua(function() 3848 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3849 3850 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 3851 _G.make_error('Error here!', 1, 1, 1, 1), 3852 }) 3853 vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, { 3854 _G.make_warning('Error there!', 2, 2, 2, 2), 3855 }) 3856 3857 vim.diagnostic.setloclist({ namespace = { _G.diagnostic_ns } }) 3858 3859 return vim.fn.getloclist(0) 3860 end) 3861 3862 eq(1, #loc_list) 3863 eq('Error here!', loc_list[1].text) 3864 end) 3865 3866 it('supports format function', function() 3867 local loc_list = exec_lua(function() 3868 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3869 3870 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 3871 _G.make_error('Error', 1, 1, 1, 1, 'foo_ls'), 3872 _G.make_error('Another error', 2, 2, 2, 2, 'foo_ls'), 3873 }) 3874 3875 vim.diagnostic.setloclist({ 3876 format = function(diagnostic) 3877 if diagnostic.lnum > 1 then 3878 return nil 3879 end 3880 3881 return string.format('%s: %s', diagnostic.source, diagnostic.message) 3882 end, 3883 }) 3884 3885 return vim.fn.getloclist(0) 3886 end) 3887 3888 eq(1, #loc_list) 3889 eq('foo_ls: Error', loc_list[1].text) 3890 end) 3891 end) 3892 3893 describe('setqflist()', function() 3894 it('updates existing diagnostics quickfix if one already exists', function() 3895 local result = exec_lua(function() 3896 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3897 3898 vim.fn.setqflist({}, ' ', { title = 'Diagnostics' }) 3899 local diagnostics_qf_id = vim.fn.getqflist({ id = 0 }).id 3900 3901 vim.diagnostic.setqflist({ title = 'Diagnostics' }) 3902 local qf_id = vim.fn.getqflist({ id = 0, nr = '$' }).id 3903 3904 return { diagnostics_qf_id, qf_id } 3905 end) 3906 3907 eq(result[1], result[2]) 3908 end) 3909 3910 it('navigates to existing diagnostics quickfix if one already exists and open=true', function() 3911 local result = exec_lua(function() 3912 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3913 3914 vim.fn.setqflist({}, ' ', { title = 'Diagnostics' }) 3915 local diagnostics_qf_id = vim.fn.getqflist({ id = 0 }).id 3916 3917 vim.fn.setqflist({}, ' ', { title = 'Other' }) 3918 3919 vim.diagnostic.setqflist({ title = 'Diagnostics', open = true }) 3920 local qf_id = vim.fn.getqflist({ id = 0 }).id 3921 3922 return { diagnostics_qf_id, qf_id } 3923 end) 3924 3925 eq(result[1], result[2]) 3926 end) 3927 3928 it('sets new diagnostics quickfix as active when open=true', function() 3929 local result = exec_lua(function() 3930 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3931 3932 vim.fn.setqflist({}, ' ', { title = 'Other' }) 3933 local other_qf_id = vim.fn.getqflist({ id = 0 }).id 3934 3935 vim.diagnostic.setqflist({ title = 'Diagnostics', open = true }) 3936 local qf_id = vim.fn.getqflist({ id = 0 }).id 3937 3938 return { other_qf_id, qf_id } 3939 end) 3940 3941 neq(result[1], result[2]) 3942 end) 3943 3944 it('opens quickfix window when open=true', function() 3945 local qf_winid = exec_lua(function() 3946 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3947 3948 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 3949 _G.make_error('Error', 1, 1, 1, 1), 3950 }) 3951 3952 vim.diagnostic.setqflist({ open = true }) 3953 3954 return vim.fn.getqflist({ winid = 0 }).winid 3955 end) 3956 3957 neq(0, qf_winid) 3958 end) 3959 3960 it('supports format function', function() 3961 local qf_list = exec_lua(function() 3962 vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 3963 3964 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 3965 _G.make_error('Error', 1, 1, 1, 1, 'foo_ls'), 3966 _G.make_error('Another error', 2, 2, 2, 2, 'foo_ls'), 3967 }) 3968 3969 vim.diagnostic.setqflist({ 3970 format = function(diagnostic) 3971 if diagnostic.lnum > 1 then 3972 return nil 3973 end 3974 3975 return string.format('%s: %s', diagnostic.source, diagnostic.message) 3976 end, 3977 }) 3978 3979 return vim.fn.getqflist() 3980 end) 3981 3982 eq(1, #qf_list) 3983 eq('foo_ls: Error', qf_list[1].text) 3984 end) 3985 end) 3986 3987 describe('match()', function() 3988 it('matches a string', function() 3989 local msg = 'ERROR: george.txt:19:84:Two plus two equals five' 3990 local diagnostic = { 3991 severity = exec_lua [[return vim.diagnostic.severity.ERROR]], 3992 lnum = 18, 3993 col = 83, 3994 end_lnum = 18, 3995 end_col = 83, 3996 message = 'Two plus two equals five', 3997 } 3998 eq( 3999 diagnostic, 4000 exec_lua(function() 4001 return vim.diagnostic.match( 4002 msg, 4003 '^(%w+): [^:]+:(%d+):(%d+):(.+)$', 4004 { 'severity', 'lnum', 'col', 'message' } 4005 ) 4006 end) 4007 ) 4008 end) 4009 4010 it('returns nil if the pattern fails to match', function() 4011 eq( 4012 nil, 4013 exec_lua(function() 4014 local msg = 'The answer to life, the universe, and everything is' 4015 return vim.diagnostic.match(msg, 'This definitely will not match', {}) 4016 end) 4017 ) 4018 end) 4019 4020 it('respects default values', function() 4021 local msg = 'anna.txt:1:Happy families are all alike' 4022 local diagnostic = { 4023 severity = exec_lua [[return vim.diagnostic.severity.INFO]], 4024 lnum = 0, 4025 col = 0, 4026 end_lnum = 0, 4027 end_col = 0, 4028 message = 'Happy families are all alike', 4029 } 4030 eq( 4031 diagnostic, 4032 exec_lua(function() 4033 return vim.diagnostic.match( 4034 msg, 4035 '^[^:]+:(%d+):(.+)$', 4036 { 'lnum', 'message' }, 4037 nil, 4038 { severity = vim.diagnostic.severity.INFO } 4039 ) 4040 end) 4041 ) 4042 end) 4043 4044 it('accepts a severity map', function() 4045 local msg = '46:FATAL:Et tu, Brute?' 4046 local diagnostic = { 4047 severity = exec_lua [[return vim.diagnostic.severity.ERROR]], 4048 lnum = 45, 4049 col = 0, 4050 end_lnum = 45, 4051 end_col = 0, 4052 message = 'Et tu, Brute?', 4053 } 4054 eq( 4055 diagnostic, 4056 exec_lua(function() 4057 return vim.diagnostic.match( 4058 msg, 4059 '^(%d+):(%w+):(.+)$', 4060 { 'lnum', 'severity', 'message' }, 4061 { FATAL = vim.diagnostic.severity.ERROR } 4062 ) 4063 end) 4064 ) 4065 end) 4066 end) 4067 4068 describe('toqflist() and fromqflist()', function() 4069 it('works', function() 4070 local result = exec_lua(function() 4071 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 4072 _G.make_error('Error 1', 0, 1, 0, 1), 4073 _G.make_error('Error 2', 1, 1, 1, 1), 4074 _G.make_warning('Warning', 2, 2, 2, 2), 4075 }) 4076 4077 local diagnostics = vim.diagnostic.get(_G.diagnostic_bufnr) 4078 vim.fn.setqflist(vim.diagnostic.toqflist(diagnostics)) 4079 local list = vim.fn.getqflist() 4080 local new_diagnostics = vim.diagnostic.fromqflist(list) 4081 4082 -- Remove extra properties not present in the return value of fromlist() 4083 for _, v in ipairs(diagnostics) do 4084 v._extmark_id = nil 4085 v.namespace = nil 4086 end 4087 4088 return { diagnostics, new_diagnostics } 4089 end) 4090 eq(result[1], result[2]) 4091 end) 4092 4093 it('merge_lines=true merges continuation lines', function() 4094 local result = exec_lua(function() 4095 local qflist = { 4096 { 4097 bufnr = 1, 4098 lnum = 10, 4099 col = 5, 4100 end_lnum = 10, 4101 end_col = 10, 4102 text = 'error: [GHC-83865]', 4103 type = 'E', 4104 nr = 0, 4105 valid = 1, 4106 }, 4107 { 4108 bufnr = 1, 4109 lnum = 0, 4110 col = 0, 4111 end_lnum = 0, 4112 end_col = 0, 4113 text = " Couldn't match expected type", 4114 type = '', 4115 nr = 0, 4116 valid = 0, 4117 }, 4118 { 4119 bufnr = 1, 4120 lnum = 0, 4121 col = 0, 4122 end_lnum = 0, 4123 end_col = 0, 4124 text = ' with actual type', 4125 type = '', 4126 nr = 0, 4127 valid = 0, 4128 }, 4129 { 4130 bufnr = 1, 4131 lnum = 20, 4132 col = 1, 4133 end_lnum = 20, 4134 end_col = 5, 4135 text = 'warning: unused', 4136 type = 'W', 4137 nr = 0, 4138 valid = 1, 4139 }, 4140 } 4141 return vim.diagnostic.fromqflist(qflist, { merge_lines = true }) 4142 end) 4143 4144 eq(2, #result) 4145 eq( 4146 "error: [GHC-83865]\n Couldn't match expected type\n with actual type", 4147 result[1].message 4148 ) 4149 eq('warning: unused', result[2].message) 4150 end) 4151 4152 it('merge_lines=false ignores continuation lines', function() 4153 local result = exec_lua(function() 4154 local qflist = { 4155 { 4156 bufnr = 1, 4157 lnum = 10, 4158 col = 5, 4159 end_lnum = 10, 4160 end_col = 10, 4161 text = 'error: main', 4162 type = 'E', 4163 nr = 0, 4164 valid = 1, 4165 }, 4166 { 4167 bufnr = 1, 4168 lnum = 0, 4169 col = 0, 4170 end_lnum = 0, 4171 end_col = 0, 4172 text = 'continuation', 4173 type = '', 4174 nr = 0, 4175 valid = 0, 4176 }, 4177 } 4178 return vim.diagnostic.fromqflist(qflist) 4179 end) 4180 4181 eq(1, #result) 4182 eq('error: main', result[1].message) 4183 end) 4184 end) 4185 4186 describe('status()', function() 4187 it('returns empty string if no diagnostics', function() 4188 local result = exec_lua(function() 4189 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {}) 4190 return vim.diagnostic.status() 4191 end) 4192 4193 eq('', result) 4194 end) 4195 4196 it('returns count for each diagnostic kind', function() 4197 local result = exec_lua(function() 4198 vim.diagnostic.set(_G.diagnostic_ns, 0, { 4199 _G.make_error('Error 1', 0, 1, 0, 1), 4200 4201 _G.make_warning('Warning 1', 2, 2, 2, 2), 4202 _G.make_warning('Warning 2', 2, 2, 2, 2), 4203 4204 _G.make_info('Info 1', 3, 3, 3, 3), 4205 _G.make_info('Info 2', 3, 3, 3, 3), 4206 _G.make_info('Info 3', 3, 3, 3, 3), 4207 4208 _G.make_hint('Hint 1', 4, 4, 4, 4), 4209 _G.make_hint('Hint 2', 4, 4, 4, 4), 4210 _G.make_hint('Hint 3', 4, 4, 4, 4), 4211 _G.make_hint('Hint 4', 4, 4, 4, 4), 4212 }) 4213 return vim.diagnostic.status() 4214 end) 4215 4216 eq( 4217 '%#DiagnosticSignError#E:1 %#DiagnosticSignWarn#W:2 %#DiagnosticSignInfo#I:3 %#DiagnosticSignHint#H:4%##', 4218 result 4219 ) 4220 4221 exec_lua('vim.cmd.enew()') 4222 4223 -- Empty diagnostics for a buffer without diagnostics 4224 eq( 4225 '', 4226 exec_lua(function() 4227 return vim.diagnostic.status() 4228 end) 4229 ) 4230 end) 4231 4232 it('uses text from diagnostic.config().status.text[severity]', function() 4233 local result = exec_lua(function() 4234 vim.diagnostic.config({ 4235 status = { 4236 text = { 4237 [vim.diagnostic.severity.ERROR] = '⨯', 4238 [vim.diagnostic.severity.WARN] = '⚠︎', 4239 }, 4240 }, 4241 }) 4242 4243 vim.diagnostic.set(_G.diagnostic_ns, 0, { 4244 _G.make_error('Error 1', 0, 1, 0, 1), 4245 _G.make_warning('Warning 1', 2, 2, 2, 2), 4246 }) 4247 4248 return vim.diagnostic.status() 4249 end) 4250 4251 eq('%#DiagnosticSignError#⨯:1 %#DiagnosticSignWarn#⚠︎:1%##', result) 4252 end) 4253 end) 4254 4255 describe('handlers', function() 4256 it('checks that a new handler is a table', function() 4257 matches( 4258 [[.*handler: expected table, got string.*]], 4259 pcall_err(exec_lua, [[ vim.diagnostic.handlers.foo = "bar" ]]) 4260 ) 4261 matches( 4262 [[.*handler: expected table, got function.*]], 4263 pcall_err(exec_lua, [[ vim.diagnostic.handlers.foo = function() end ]]) 4264 ) 4265 end) 4266 4267 it('can add new handlers', function() 4268 eq( 4269 true, 4270 exec_lua(function() 4271 local handler_called = false 4272 vim.diagnostic.handlers.test = { 4273 show = function(namespace, bufnr, diagnostics, opts) 4274 assert(namespace == _G.diagnostic_ns) 4275 assert(bufnr == _G.diagnostic_bufnr) 4276 assert(#diagnostics == 1) 4277 assert(opts.test.some_opt == 42) 4278 handler_called = true 4279 end, 4280 } 4281 4282 vim.diagnostic.config({ test = { some_opt = 42 } }) 4283 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 4284 _G.make_warning('Warning', 0, 0, 0, 0), 4285 }) 4286 return handler_called 4287 end) 4288 ) 4289 end) 4290 4291 it('can disable handlers by setting the corresponding option to false', function() 4292 eq( 4293 false, 4294 exec_lua(function() 4295 local handler_called = false 4296 vim.diagnostic.handlers.test = { 4297 show = function(_, _, _, _) 4298 handler_called = true 4299 end, 4300 } 4301 4302 vim.diagnostic.config({ test = false }) 4303 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 4304 _G.make_warning('Warning', 0, 0, 0, 0), 4305 }) 4306 return handler_called 4307 end) 4308 ) 4309 end) 4310 4311 it("always calls a handler's hide function if defined", function() 4312 eq( 4313 { false, true }, 4314 exec_lua(function() 4315 local hide_called = false 4316 local show_called = false 4317 vim.diagnostic.handlers.test = { 4318 show = function(_, _, _, _) 4319 show_called = true 4320 end, 4321 hide = function(namespace, bufnr) 4322 assert(namespace == _G.diagnostic_ns) 4323 assert(bufnr == _G.diagnostic_bufnr) 4324 hide_called = true 4325 end, 4326 } 4327 4328 vim.diagnostic.config({ test = false }) 4329 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 4330 _G.make_warning('Warning', 0, 0, 0, 0), 4331 }) 4332 vim.diagnostic.hide(_G.diagnostic_ns, _G.diagnostic_bufnr) 4333 return { show_called, hide_called } 4334 end) 4335 ) 4336 end) 4337 4338 it('triggers the autocommand when diagnostics are set', function() 4339 eq( 4340 { true, true }, 4341 exec_lua(function() 4342 -- Set a different buffer as current to test that <abuf> is being set properly in 4343 -- DiagnosticChanged callbacks 4344 local tmp = vim.api.nvim_create_buf(false, true) 4345 vim.api.nvim_set_current_buf(tmp) 4346 4347 local triggered = {} 4348 vim.api.nvim_create_autocmd('DiagnosticChanged', { 4349 callback = function(args) 4350 triggered = { args.buf, #args.data.diagnostics } 4351 end, 4352 }) 4353 vim.api.nvim_buf_set_name(_G.diagnostic_bufnr, 'test | test') 4354 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 4355 _G.make_error('Diagnostic', 0, 0, 0, 0), 4356 }) 4357 return { 4358 triggered[1] == _G.diagnostic_bufnr, 4359 triggered[2] == 1, 4360 } 4361 end) 4362 ) 4363 end) 4364 4365 it('triggers the autocommand when diagnostics are cleared', function() 4366 eq( 4367 true, 4368 exec_lua(function() 4369 local tmp = vim.api.nvim_create_buf(false, true) 4370 vim.api.nvim_set_current_buf(tmp) 4371 vim.g.diagnostic_autocmd_triggered = 0 4372 vim.cmd( 4373 'autocmd DiagnosticChanged * let g:diagnostic_autocmd_triggered = +expand("<abuf>")' 4374 ) 4375 vim.api.nvim_buf_set_name(_G.diagnostic_bufnr, 'test | test') 4376 vim.diagnostic.reset(_G.diagnostic_ns, _G.diagnostic_bufnr) 4377 return vim.g.diagnostic_autocmd_triggered == _G.diagnostic_bufnr 4378 end) 4379 ) 4380 end) 4381 4382 it('is_enabled', function() 4383 eq( 4384 { false, false, false, false, false }, 4385 exec_lua(function() 4386 vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { 4387 _G.make_error('Diagnostic #1', 1, 1, 1, 1), 4388 }) 4389 vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) 4390 vim.diagnostic.enable(false) 4391 return { 4392 vim.diagnostic.is_enabled(), 4393 vim.diagnostic.is_enabled { bufnr = 0 }, 4394 vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr }, 4395 vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }, 4396 vim.diagnostic.is_enabled { bufnr = 0, ns_id = _G.diagnostic_ns }, 4397 } 4398 end) 4399 ) 4400 4401 eq( 4402 { true, true, true, true, true }, 4403 exec_lua(function() 4404 vim.diagnostic.enable() 4405 return { 4406 vim.diagnostic.is_enabled(), 4407 vim.diagnostic.is_enabled { bufnr = 0 }, 4408 vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr }, 4409 vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }, 4410 vim.diagnostic.is_enabled { bufnr = 0, ns_id = _G.diagnostic_ns }, 4411 } 4412 end) 4413 ) 4414 end) 4415 end) 4416 end)