Skip to content
This repository has been archived by the owner on Aug 12, 2023. It is now read-only.

Commit

Permalink
Merge pull request #320 from jose-elias-alvarez/check-changedtick
Browse files Browse the repository at this point in the history
fix(diagnostics): don't call handler if buffer changed since request
  • Loading branch information
Jose Alvarez committed Nov 12, 2021
2 parents 6d52853 + 3e73907 commit a3ded9b
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 5 deletions.
22 changes: 20 additions & 2 deletions lua/null-ls/diagnostics.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ local s = require("null-ls.state")
local c = require("null-ls.config")
local methods = require("null-ls.methods")

local api = vim.api

local M = {}

-- assume 1-indexed ranges
Expand Down Expand Up @@ -36,12 +38,17 @@ local postprocess = function(diagnostic, _, generator)
diagnostic.message = formatted
end

-- track last changedtick to only send most recent diagnostics
local last_changedtick = {}

M.handler = function(original_params)
if not original_params.textDocument then
return
end

local method, uri = original_params.method, original_params.textDocument.uri
if method == methods.lsp.DID_CLOSE then
last_changedtick[uri] = nil
s.clear_cache(uri)
return
end
Expand All @@ -52,6 +59,11 @@ M.handler = function(original_params)

local params = u.make_params(original_params, methods.map[method])
local handler = u.resolve_handler(methods.lsp.PUBLISH_DIAGNOSTICS)
local bufnr = vim.uri_to_bufnr(uri)

local changedtick = original_params.textDocument.version or api.nvim_buf_get_changedtick(bufnr)
last_changedtick[uri] = changedtick

require("null-ls.generators").run_registered({
filetype = params.ft,
method = methods.map[method],
Expand All @@ -61,7 +73,14 @@ M.handler = function(original_params)
u.debug_log("received diagnostics from generators")
u.debug_log(diagnostics)

local bufnr = vim.uri_to_bufnr(uri)
if
last_changedtick[uri] -- nil if received didExit notification
and last_changedtick[uri] > changedtick -- buffer changed between notification and callback
then
u.debug_log("buffer changed; ignoring received diagnostics")
return
end

if u.has_version("0.5.1") then
handler(nil, { diagnostics = diagnostics, uri = uri }, {
method = methods.lsp.PUBLISH_DIAGNOSTICS,
Expand All @@ -72,7 +91,6 @@ M.handler = function(original_params)
handler(nil, methods.lsp.PUBLISH_DIAGNOSTICS, {
diagnostics = diagnostics,
uri = uri,
---@diagnostic disable-next-line: redundant-parameter
}, original_params.client_id, bufnr)
end
end,
Expand Down
38 changes: 35 additions & 3 deletions test/spec/diagnostics_spec.lua
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
local mock = require("luassert.mock")
local stub = require("luassert.stub")

local methods = require("null-ls.methods")
local generators = require("null-ls.generators")
local u = require("null-ls.utils")
local s = require("null-ls.state")
local c = require("null-ls.config")
local methods = require("null-ls.methods")
local generators = require("null-ls.generators")

local lsp = mock(vim.lsp, "true")

Expand All @@ -22,7 +22,7 @@ describe("diagnostics", function()
local mock_params
before_each(function()
mock_params = {
textDocument = { uri = mock_uri },
textDocument = { uri = mock_uri, version = 1 },
client_id = mock_client_id,
method = methods.lsp.DID_OPEN,
}
Expand All @@ -41,6 +41,14 @@ describe("diagnostics", function()
c.reset()
end)

it("should call clear_cache with uri when method is DID_CLOSE", function()
mock_params.method = methods.lsp.DID_CLOSE

diagnostics.handler(mock_params)

assert.stub(s.clear_cache).was_called_with(mock_params.textDocument.uri)
end)

it("should call clear_cache with uri when method is DID_CHANGE", function()
mock_params.method = methods.lsp.DID_CHANGE

Expand All @@ -55,6 +63,30 @@ describe("diagnostics", function()
assert.stub(u.make_params).was_called_with(mock_params, methods.internal.DIAGNOSTICS)
end)

describe("changedtick tracking", function()
it("should call handler on each callback if buffer did not change", function()
diagnostics.handler(mock_params)
diagnostics.handler(mock_params)

generators.run_registered.calls[1].refs[1].callback("diagnostics")
generators.run_registered.calls[2].refs[1].callback("diagnostics")

assert.stub(lsp.handlers[methods.lsp.PUBLISH_DIAGNOSTICS]).was_called(2)
end)

it("should call handler only once if buffer changed in between callbacks", function()
diagnostics.handler(mock_params)
local new_params = vim.deepcopy(mock_params)
new_params.textDocument.version = 9999
diagnostics.handler(new_params)

generators.run_registered.calls[1].refs[1].callback("diagnostics")
generators.run_registered.calls[2].refs[1].callback("diagnostics")

assert.stub(lsp.handlers[methods.lsp.PUBLISH_DIAGNOSTICS]).was_called(1)
end)
end)

describe("handler", function()
local has = stub(vim.fn, "has")
after_each(function()
Expand Down

0 comments on commit a3ded9b

Please sign in to comment.