aboutsummaryrefslogtreecommitdiff
path: root/test/functional/plugin/lsp/diagnostic_spec.lua
diff options
context:
space:
mode:
authorTJ DeVries <devries.timothyj@gmail.com>2020-11-12 22:21:34 -0500
committerGitHub <noreply@github.com>2020-11-12 22:21:34 -0500
commitf75be5e9d510d5369c572cf98e78d9480df3b0bb (patch)
treee25baab19bcb47ca0d2edcf0baa18b71cfd03f9e /test/functional/plugin/lsp/diagnostic_spec.lua
parent4ae31c46f75aef7d7a80dd2a8d269c168806a1bd (diff)
downloadrneovim-f75be5e9d510d5369c572cf98e78d9480df3b0bb.tar.gz
rneovim-f75be5e9d510d5369c572cf98e78d9480df3b0bb.tar.bz2
rneovim-f75be5e9d510d5369c572cf98e78d9480df3b0bb.zip
lsp: vim.lsp.diagnostic (#12655)
Breaking Changes: - Deprecated all `vim.lsp.util.{*diagnostics*}()` functions. - Instead, all functions must be found in vim.lsp.diagnostic - For now, they issue a warning ONCE per neovim session. In a "little while" we will remove them completely. - `vim.lsp.callbacks` has moved to `vim.lsp.handlers`. - For a "little while" we will just redirect `vim.lsp.callbacks` to `vim.lsp.handlers`. However, we will remove this at some point, so it is recommended that you change all of your references to `callbacks` into `handlers`. - This also means that for functions like |vim.lsp.start_client()| and similar, keyword style arguments have moved from "callbacks" to "handlers". Once again, these are currently being forward, but will cease to be forwarded in a "little while". - Changed the highlight groups for LspDiagnostic highlight as they were inconsistently named. - For more information, see |lsp-highlight-diagnostics| - Changed the sign group names as well, to be consistent with |lsp-highlight-diagnostics| General Enhancements: - Rewrote much of the getting started help document for lsp. It also provides a much nicer configuration strategy, so as to not recommend globally overwriting builtin neovim mappings. LSP Enhancements: - Introduced the concept of |lsp-handlers| which will allow much better customization for users without having to copy & paste entire files / functions / etc. Diagnostic Enhancements: - "goto next diagnostic" |vim.lsp.diagnostic.goto_next()| - "goto prev diagnostic" |vim.lsp.diagnostic.goto_prev()| - For each of the gotos, auto open diagnostics is available as a configuration option - Configurable diagnostic handling: - See |vim.lsp.diagnostic.on_publish_diagnostics()| - Delay display until after insert mode - Configure signs - Configure virtual text - Configure underline - Set the location list with the buffers diagnostics. - See |vim.lsp.diagnostic.set_loclist()| - Better performance for getting counts and line diagnostics - They are now cached on save, to enhance lookups. - Particularly useful for checking in statusline, etc. - Actual testing :) - See ./test/functional/plugin/lsp/diagnostic_spec.lua - Added `guisp` for underline highlighting NOTE: "a little while" means enough time to feel like most plugins and plugin authors have had a chance to refactor their code to use the updated calls. Then we will remove them completely. There is no need to keep them, because we don't have any released version of neovim that exposes these APIs. I'm trying to be nice to people following HEAD :) Co-authored: [Twitch Chat 2020](https://twitch.tv/teej_dv)
Diffstat (limited to 'test/functional/plugin/lsp/diagnostic_spec.lua')
-rw-r--r--test/functional/plugin/lsp/diagnostic_spec.lua767
1 files changed, 767 insertions, 0 deletions
diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua
new file mode 100644
index 0000000000..0fb55da4bd
--- /dev/null
+++ b/test/functional/plugin/lsp/diagnostic_spec.lua
@@ -0,0 +1,767 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local exec_lua = helpers.exec_lua
+local eq = helpers.eq
+local nvim = helpers.nvim
+
+describe('vim.lsp.diagnostic', function()
+ local fake_uri
+
+ before_each(function()
+ clear()
+
+ exec_lua [[
+ require('vim.lsp')
+
+ make_range = function(x1, y1, x2, y2)
+ return { start = { line = x1, character = y1 }, ['end'] = { line = x2, character = y2 } }
+ end
+
+ make_error = function(msg, x1, y1, x2, y2)
+ return {
+ range = make_range(x1, y1, x2, y2),
+ message = msg,
+ severity = 1,
+ }
+ end
+
+ make_warning = function(msg, x1, y1, x2, y2)
+ return {
+ range = make_range(x1, y1, x2, y2),
+ message = msg,
+ severity = 2,
+ }
+ end
+
+ make_information = function(msg, x1, y1, x2, y2)
+ return {
+ range = make_range(x1, y1, x2, y2),
+ message = msg,
+ severity = 3,
+ }
+ end
+
+ count_of_extmarks_for_client = function(bufnr, client_id)
+ return #vim.api.nvim_buf_get_extmarks(
+ bufnr, vim.lsp.diagnostic._get_diagnostic_namespace(client_id), 0, -1, {}
+ )
+ end
+ ]]
+
+ fake_uri = "file://fake/uri"
+
+ exec_lua([[
+ fake_uri = ...
+ diagnostic_bufnr = vim.uri_to_bufnr(fake_uri)
+ local lines = {"1st line of text", "2nd line of text", "wow", "cool", "more", "lines"}
+ vim.fn.bufload(diagnostic_bufnr)
+ vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, 1, false, lines)
+ return diagnostic_bufnr
+ ]], fake_uri)
+ end)
+
+ after_each(function()
+ clear()
+ end)
+
+ describe('vim.lsp.diagnostic', function()
+ describe('handle_publish_diagnostics', function()
+ it('should be able to save and count a single client error', function()
+ eq(1, exec_lua [[
+ vim.lsp.diagnostic.save(
+ {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ }, 0, 1
+ )
+ return vim.lsp.diagnostic.get_count(0, "Error", 1)
+ ]])
+ end)
+
+ it('should be able to save and count from two clients', function()
+ eq(2, exec_lua [[
+ vim.lsp.diagnostic.save(
+ {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ make_error('Diagnostic #2', 2, 1, 2, 1),
+ }, 0, 1
+ )
+ return vim.lsp.diagnostic.get_count(0, "Error", 1)
+ ]])
+ end)
+
+ it('should be able to save and count from multiple clients', function()
+ eq({1, 1, 2}, exec_lua [[
+ vim.lsp.diagnostic.save(
+ {
+ make_error('Diagnostic From Server 1', 1, 1, 1, 1),
+ }, 0, 1
+ )
+ vim.lsp.diagnostic.save(
+ {
+ make_error('Diagnostic From Server 2', 1, 1, 1, 1),
+ }, 0, 2
+ )
+ return {
+ -- Server 1
+ vim.lsp.diagnostic.get_count(0, "Error", 1),
+ -- Server 2
+ vim.lsp.diagnostic.get_count(0, "Error", 2),
+ -- All servers
+ vim.lsp.diagnostic.get_count(0, "Error", nil),
+ }
+ ]])
+ end)
+
+ it('should be able to save and count from multiple clients with respect to severity', function()
+ eq({3, 0, 3}, exec_lua [[
+ vim.lsp.diagnostic.save(
+ {
+ make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
+ make_error('Diagnostic From Server 1:2', 2, 2, 2, 2),
+ make_error('Diagnostic From Server 1:3', 2, 3, 3, 2),
+ }, 0, 1
+ )
+ vim.lsp.diagnostic.save(
+ {
+ make_warning('Warning From Server 2', 3, 3, 3, 3),
+ }, 0, 2
+ )
+ return {
+ -- Server 1
+ vim.lsp.diagnostic.get_count(0, "Error", 1),
+ -- Server 2
+ vim.lsp.diagnostic.get_count(0, "Error", 2),
+ -- All servers
+ vim.lsp.diagnostic.get_count(0, "Error", nil),
+ }
+ ]])
+ end)
+
+ it('should handle one server clearing highlights while the other still has highlights', function()
+ -- 1 Error (1)
+ -- 1 Warning (2)
+ -- 1 Warning (2) + 1 Warning (1)
+ -- 2 highlights and 2 underlines (since error)
+ -- 1 highlight + 1 underline
+ local all_highlights = {1, 1, 2, 4, 2}
+ eq(all_highlights, exec_lua [[
+ local server_1_diags = {
+ make_error("Error 1", 1, 1, 1, 5),
+ make_warning("Warning on Server 1", 2, 1, 2, 5),
+ }
+ local server_2_diags = {
+ make_warning("Warning 1", 2, 1, 2, 5),
+ }
+
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, { uri = fake_uri, diagnostics = server_1_diags }, 1)
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, { uri = fake_uri, diagnostics = server_2_diags }, 2)
+ return {
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", 2),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", nil),
+ count_of_extmarks_for_client(diagnostic_bufnr, 1),
+ count_of_extmarks_for_client(diagnostic_bufnr, 2),
+ }
+ ]])
+
+ -- Clear diagnostics from server 1, and make sure we have the right amount of stuff for client 2
+ eq({1, 1, 2, 0, 2}, exec_lua [[
+ vim.lsp.diagnostic.clear(diagnostic_bufnr, 1)
+ return {
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", 2),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", nil),
+ count_of_extmarks_for_client(diagnostic_bufnr, 1),
+ count_of_extmarks_for_client(diagnostic_bufnr, 2),
+ }
+ ]])
+
+ -- Show diagnostics from server 1 again
+ eq(all_highlights, exec_lua([[
+ vim.lsp.diagnostic.display(nil, diagnostic_bufnr, 1)
+ return {
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", 2),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", nil),
+ count_of_extmarks_for_client(diagnostic_bufnr, 1),
+ count_of_extmarks_for_client(diagnostic_bufnr, 2),
+ }
+ ]]))
+ end)
+
+ describe('get_next_diagnostic_pos', function()
+ it('can find the next pos with only one client', function()
+ eq({1, 1}, exec_lua [[
+ vim.lsp.diagnostic.save(
+ {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ }, diagnostic_bufnr, 1
+ )
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ return vim.lsp.diagnostic.get_next_pos()
+ ]])
+ end)
+
+ it('can find next pos with two errors', function()
+ eq({4, 4}, exec_lua [[
+ vim.lsp.diagnostic.save(
+ {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ make_error('Diagnostic #2', 4, 4, 4, 4),
+ }, diagnostic_bufnr, 1
+ )
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {3, 1})
+ return vim.lsp.diagnostic.get_next_pos { client_id = 1 }
+ ]])
+ end)
+
+ it('can cycle when position is past error', function()
+ eq({1, 1}, exec_lua [[
+ vim.lsp.diagnostic.save(
+ {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ }, diagnostic_bufnr, 1
+ )
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {3, 1})
+ return vim.lsp.diagnostic.get_next_pos { client_id = 1 }
+ ]])
+ end)
+
+ it('will not cycle when wrap is off', function()
+ eq(false, exec_lua [[
+ vim.lsp.diagnostic.save(
+ {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ }, diagnostic_bufnr, 1
+ )
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {3, 1})
+ return vim.lsp.diagnostic.get_next_pos { client_id = 1, wrap = false }
+ ]])
+ end)
+
+ it('can cycle even from the last line', function()
+ eq({4, 4}, exec_lua [[
+ vim.lsp.diagnostic.save(
+ {
+ make_error('Diagnostic #2', 4, 4, 4, 4),
+ }, diagnostic_bufnr, 1
+ )
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {vim.api.nvim_buf_line_count(0), 1})
+ return vim.lsp.diagnostic.get_prev_pos { client_id = 1 }
+ ]])
+ end)
+ end)
+
+ describe('get_prev_diagnostic_pos', function()
+ it('can find the prev pos with only one client', function()
+ eq({1, 1}, exec_lua [[
+ vim.lsp.diagnostic.save(
+ {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ }, diagnostic_bufnr, 1
+ )
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {3, 1})
+ return vim.lsp.diagnostic.get_prev_pos()
+ ]])
+ end)
+
+ it('can find prev pos with two errors', function()
+ eq({1, 1}, exec_lua [[
+ vim.lsp.diagnostic.save(
+ {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ make_error('Diagnostic #2', 4, 4, 4, 4),
+ }, diagnostic_bufnr, 1
+ )
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {3, 1})
+ return vim.lsp.diagnostic.get_prev_pos { client_id = 1 }
+ ]])
+ end)
+
+ it('can cycle when position is past error', function()
+ eq({4, 4}, exec_lua [[
+ vim.lsp.diagnostic.save(
+ {
+ make_error('Diagnostic #2', 4, 4, 4, 4),
+ }, diagnostic_bufnr, 1
+ )
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {3, 1})
+ return vim.lsp.diagnostic.get_prev_pos { client_id = 1 }
+ ]])
+ end)
+
+ it('respects wrap parameter', function()
+ eq(false, exec_lua [[
+ vim.lsp.diagnostic.save(
+ {
+ make_error('Diagnostic #2', 4, 4, 4, 4),
+ }, diagnostic_bufnr, 1
+ )
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {3, 1})
+ return vim.lsp.diagnostic.get_prev_pos { client_id = 1, wrap = false}
+ ]])
+ end)
+ end)
+ end)
+ end)
+
+ describe("vim.lsp.diagnostic.get_line_diagnostics", function()
+ it('should return an empty table when no diagnostics are present', function()
+ eq({}, exec_lua [[return vim.lsp.diagnostic.get_line_diagnostics(diagnostic_bufnr, 1)]])
+ end)
+
+ it('should return all diagnostics when no severity is supplied', function()
+ eq(2, exec_lua [[
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, {
+ uri = fake_uri,
+ diagnostics = {
+ make_error("Error 1", 1, 1, 1, 5),
+ make_warning("Warning on Server 1", 1, 1, 2, 5),
+ make_error("Error On Other Line", 2, 1, 1, 5),
+ }
+ }, 1)
+
+ return #vim.lsp.diagnostic.get_line_diagnostics(diagnostic_bufnr, 1)
+ ]])
+ end)
+
+ it('should return only requested diagnostics when severity_limit is supplied', function()
+ eq(2, exec_lua [[
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, {
+ uri = fake_uri,
+ diagnostics = {
+ make_error("Error 1", 1, 1, 1, 5),
+ make_warning("Warning on Server 1", 1, 1, 2, 5),
+ make_information("Ignored information", 1, 1, 2, 5),
+ make_error("Error On Other Line", 2, 1, 1, 5),
+ }
+ }, 1)
+
+ return #vim.lsp.diagnostic.get_line_diagnostics(diagnostic_bufnr, 1, { severity_limit = "Warning" })
+ ]])
+ end)
+ end)
+
+ describe("vim.lsp.diagnostic.on_publish_diagnostics", function()
+ it('can use functions for config values', function()
+ exec_lua [[
+ vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
+ virtual_text = function() return true end,
+ })(nil, nil, {
+ uri = fake_uri,
+ diagnostics = {
+ make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ }
+ }, 1
+ )
+ ]]
+
+ eq(1, exec_lua [[return vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1)]])
+ eq(2, exec_lua [[return count_of_extmarks_for_client(diagnostic_bufnr, 1)]])
+
+ -- Now, don't enable virtual text.
+ -- We should have one less extmark displayed.
+ exec_lua [[
+ vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
+ virtual_text = function() return false end,
+ })(nil, nil, {
+ uri = fake_uri,
+ diagnostics = {
+ make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ }
+ }, 1
+ )
+ ]]
+
+ eq(1, exec_lua [[return vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1)]])
+ eq(1, exec_lua [[return count_of_extmarks_for_client(diagnostic_bufnr, 1)]])
+ end)
+
+ it('can perform updates after insert_leave', function()
+ exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]]
+ nvim("input", "o")
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+
+ -- Save the diagnostics
+ exec_lua [[
+ vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
+ update_in_insert = false,
+ })(nil, nil, {
+ uri = fake_uri,
+ diagnostics = {
+ make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ }
+ }, 1
+ )
+ ]]
+
+ -- No diagnostics displayed yet.
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+ eq(1, exec_lua [[return vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1)]])
+ eq(0, exec_lua [[return count_of_extmarks_for_client(diagnostic_bufnr, 1)]])
+
+ nvim("input", "<esc>")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+
+ eq(1, exec_lua [[return vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1)]])
+ eq(2, exec_lua [[return count_of_extmarks_for_client(diagnostic_bufnr, 1)]])
+ end)
+
+ it('does not perform updates when not needed', function()
+ exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]]
+ nvim("input", "o")
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+
+ -- Save the diagnostics
+ exec_lua [[
+ PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
+ update_in_insert = false,
+ virtual_text = true,
+ })
+
+ -- Count how many times we call display.
+ SetVirtualTextOriginal = vim.lsp.diagnostic.set_virtual_text
+
+ DisplayCount = 0
+ vim.lsp.diagnostic.set_virtual_text = function(...)
+ DisplayCount = DisplayCount + 1
+ return SetVirtualTextOriginal(...)
+ end
+
+ PublishDiagnostics(nil, nil, {
+ uri = fake_uri,
+ diagnostics = {
+ make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ }
+ }, 1
+ )
+ ]]
+
+ -- No diagnostics displayed yet.
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+ eq(1, exec_lua [[return vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1)]])
+ eq(0, exec_lua [[return count_of_extmarks_for_client(diagnostic_bufnr, 1)]])
+ eq(0, exec_lua [[return DisplayCount]])
+
+ nvim("input", "<esc>")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+
+ eq(1, exec_lua [[return vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1)]])
+ eq(2, exec_lua [[return count_of_extmarks_for_client(diagnostic_bufnr, 1)]])
+ eq(1, exec_lua [[return DisplayCount]])
+
+ -- Go in and out of insert mode one more time.
+ nvim("input", "o")
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+
+ nvim("input", "<esc>")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+
+ -- Should not have set the virtual text again.
+ eq(1, exec_lua [[return DisplayCount]])
+ end)
+
+ it('never sets virtual text, in combination with insert leave', function()
+ exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]]
+ nvim("input", "o")
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+
+ -- Save the diagnostics
+ exec_lua [[
+ PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
+ update_in_insert = false,
+ virtual_text = false,
+ })
+
+ -- Count how many times we call display.
+ SetVirtualTextOriginal = vim.lsp.diagnostic.set_virtual_text
+
+ DisplayCount = 0
+ vim.lsp.diagnostic.set_virtual_text = function(...)
+ DisplayCount = DisplayCount + 1
+ return SetVirtualTextOriginal(...)
+ end
+
+ PublishDiagnostics(nil, nil, {
+ uri = fake_uri,
+ diagnostics = {
+ make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ }
+ }, 1
+ )
+ ]]
+
+ -- No diagnostics displayed yet.
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+ eq(1, exec_lua [[return vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1)]])
+ eq(0, exec_lua [[return count_of_extmarks_for_client(diagnostic_bufnr, 1)]])
+ eq(0, exec_lua [[return DisplayCount]])
+
+ nvim("input", "<esc>")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+
+ eq(1, exec_lua [[return vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1)]])
+ eq(1, exec_lua [[return count_of_extmarks_for_client(diagnostic_bufnr, 1)]])
+ eq(0, exec_lua [[return DisplayCount]])
+
+ -- Go in and out of insert mode one more time.
+ nvim("input", "o")
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+
+ nvim("input", "<esc>")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+
+ -- Should not have set the virtual text still.
+ eq(0, exec_lua [[return DisplayCount]])
+ end)
+
+ it('can perform updates while in insert mode, if desired', function()
+ exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]]
+ nvim("input", "o")
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+
+ -- Save the diagnostics
+ exec_lua [[
+ vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
+ update_in_insert = true,
+ })(nil, nil, {
+ uri = fake_uri,
+ diagnostics = {
+ make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ }
+ }, 1
+ )
+ ]]
+
+ -- Diagnostics are displayed, because the user wanted them that way!
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+ eq(1, exec_lua [[return vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1)]])
+ eq(2, exec_lua [[return count_of_extmarks_for_client(diagnostic_bufnr, 1)]])
+
+ nvim("input", "<esc>")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+
+ eq(1, exec_lua [[return vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1)]])
+ eq(2, exec_lua [[return count_of_extmarks_for_client(diagnostic_bufnr, 1)]])
+ end)
+
+ it('allows configuring the virtual text via vim.lsp.with', function()
+ local expected_spacing = 10
+ local extmarks = exec_lua([[
+ PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
+ virtual_text = {
+ spacing = ...,
+ },
+ })
+
+ PublishDiagnostics(nil, nil, {
+ uri = fake_uri,
+ diagnostics = {
+ make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ }
+ }, 1
+ )
+
+ return vim.api.nvim_buf_get_extmarks(
+ diagnostic_bufnr,
+ vim.lsp.diagnostic._get_diagnostic_namespace(1),
+ 0,
+ -1,
+ { details = true }
+ )
+ ]], expected_spacing)
+
+ local virt_text = extmarks[1][4].virt_text
+ local spacing = virt_text[1][1]
+
+ eq(expected_spacing, #spacing)
+ end)
+
+
+ it('allows configuring the virtual text via vim.lsp.with using a function', function()
+ local expected_spacing = 10
+ local extmarks = exec_lua([[
+ spacing = ...
+
+ PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
+ virtual_text = function()
+ return {
+ spacing = spacing,
+ }
+ end,
+ })
+
+ PublishDiagnostics(nil, nil, {
+ uri = fake_uri,
+ diagnostics = {
+ make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ }
+ }, 1
+ )
+
+ return vim.api.nvim_buf_get_extmarks(
+ diagnostic_bufnr,
+ vim.lsp.diagnostic._get_diagnostic_namespace(1),
+ 0,
+ -1,
+ { details = true }
+ )
+ ]], expected_spacing)
+
+ local virt_text = extmarks[1][4].virt_text
+ local spacing = virt_text[1][1]
+
+ eq(expected_spacing, #spacing)
+ end)
+ end)
+
+ describe('lsp.util.show_line_diagnostics', function()
+ it('creates floating window and returns popup bufnr and winnr if current line contains diagnostics', function()
+ -- Two lines:
+ -- Diagnostic:
+ -- 1. <msg>
+ eq(2, exec_lua [[
+ local buffer = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(buffer, 0, -1, false, {
+ "testing";
+ "123";
+ })
+ local diagnostics = {
+ {
+ range = {
+ start = { line = 0; character = 1; };
+ ["end"] = { line = 0; character = 3; };
+ };
+ severity = vim.lsp.protocol.DiagnosticSeverity.Error;
+ message = "Syntax error";
+ },
+ }
+ vim.api.nvim_win_set_buf(0, buffer)
+ vim.lsp.diagnostic.save(diagnostics, buffer, 1)
+ local popup_bufnr, winnr = vim.lsp.diagnostic.show_line_diagnostics()
+ return #vim.api.nvim_buf_get_lines(popup_bufnr, 0, -1, false)
+ ]])
+ end)
+
+ it('creates floating window and returns popup bufnr and winnr without header, if requested', function()
+ -- One line (since no header):
+ -- 1. <msg>
+ eq(1, exec_lua [[
+ local buffer = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(buffer, 0, -1, false, {
+ "testing";
+ "123";
+ })
+ local diagnostics = {
+ {
+ range = {
+ start = { line = 0; character = 1; };
+ ["end"] = { line = 0; character = 3; };
+ };
+ severity = vim.lsp.protocol.DiagnosticSeverity.Error;
+ message = "Syntax error";
+ },
+ }
+ vim.api.nvim_win_set_buf(0, buffer)
+ vim.lsp.diagnostic.save(diagnostics, buffer, 1)
+ local popup_bufnr, winnr = vim.lsp.diagnostic.show_line_diagnostics { show_header = false }
+ return #vim.api.nvim_buf_get_lines(popup_bufnr, 0, -1, false)
+ ]])
+ end)
+ end)
+
+ describe('set_signs', function()
+ -- TODO(tjdevries): Find out why signs are not displayed when set from Lua...??
+ pending('sets signs by default', function()
+ exec_lua [[
+ PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
+ update_in_insert = true,
+ signs = true,
+ })
+
+ local diagnostics = {
+ make_error('Delayed Diagnostic', 1, 1, 1, 2),
+ make_error('Delayed Diagnostic', 3, 3, 3, 3),
+ }
+
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, {
+ uri = fake_uri,
+ diagnostics = diagnostics
+ }, 1
+ )
+
+ vim.lsp.diagnostic.set_signs(diagnostics, diagnostic_bufnr, 1)
+ -- return vim.fn.sign_getplaced()
+ ]]
+
+ nvim("input", "o")
+ nvim("input", "<esc>")
+
+ -- TODO(tjdevries): Find a way to get the signs to display in the test...
+ eq(nil, exec_lua [[
+ return im.fn.sign_getplaced()[1].signs
+ ]])
+ end)
+ end)
+
+ describe('set_loclist()', function()
+ it('sets diagnostics in lnum order', function()
+ local loc_list = exec_lua [[
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, {
+ uri = fake_uri,
+ diagnostics = {
+ make_error('Farther Diagnostic', 4, 4, 4, 4),
+ make_error('Lower Diagnostic', 1, 1, 1, 1),
+ }
+ }, 1
+ )
+
+ vim.lsp.diagnostic.set_loclist()
+
+ return vim.fn.getloclist(0)
+ ]]
+
+ assert(loc_list[1].lnum < loc_list[2].lnum)
+ end)
+
+ it('sets diagnostics in lnum order, regardless of client', function()
+ local loc_list = exec_lua [[
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, {
+ uri = fake_uri,
+ diagnostics = {
+ make_error('Lower Diagnostic', 1, 1, 1, 1),
+ }
+ }, 1
+ )
+
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, {
+ uri = fake_uri,
+ diagnostics = {
+ make_warning('Farther Diagnostic', 4, 4, 4, 4),
+ }
+ }, 2
+ )
+
+ vim.lsp.diagnostic.set_loclist()
+
+ return vim.fn.getloclist(0)
+ ]]
+
+ assert(loc_list[1].lnum < loc_list[2].lnum)
+ end)
+ end)
+end)