mirror of
https://github.com/dense-analysis/ale.git
synced 2025-12-06 12:44:23 +08:00
#3600 Implement pull model with Neovim Client
Some checks failed
CI / build_image (push) Has been cancelled
CI / test_ale (--linters-only) (push) Has been cancelled
CI / test_ale (--lua-only) (push) Has been cancelled
CI / test_ale (--neovim-07-only) (push) Has been cancelled
CI / test_ale (--neovim-08-only) (push) Has been cancelled
CI / test_ale (--vim-80-only) (push) Has been cancelled
CI / test_ale (--vim-90-only) (push) Has been cancelled
Some checks failed
CI / build_image (push) Has been cancelled
CI / test_ale (--linters-only) (push) Has been cancelled
CI / test_ale (--lua-only) (push) Has been cancelled
CI / test_ale (--neovim-07-only) (push) Has been cancelled
CI / test_ale (--neovim-08-only) (push) Has been cancelled
CI / test_ale (--vim-80-only) (push) Has been cancelled
CI / test_ale (--vim-90-only) (push) Has been cancelled
Implement the diagnostics pull model with the LSP Neovim client. We must handle messages a little different and tweak client capabilities for pull diagnostics to work through the Neovim client.
This commit is contained in:
@@ -100,7 +100,7 @@ endfunction
|
||||
" Handle LSP diagnostics for a given URI.
|
||||
" The special value 'unchanged' can be used for diagnostics to indicate
|
||||
" that diagnostics haven't changed since we last checked.
|
||||
function! s:HandleLSPDiagnostics(conn_id, uri, diagnostics) abort
|
||||
function! ale#lsp_linter#HandleLSPDiagnostics(conn_id, uri, diagnostics) abort
|
||||
let l:linter = get(s:lsp_linter_map, a:conn_id)
|
||||
|
||||
if empty(l:linter)
|
||||
@@ -233,14 +233,14 @@ function! ale#lsp_linter#HandleLSPResponse(conn_id, response) abort
|
||||
let l:uri = a:response.params.uri
|
||||
let l:diagnostics = a:response.params.diagnostics
|
||||
|
||||
call s:HandleLSPDiagnostics(a:conn_id, l:uri, l:diagnostics)
|
||||
call ale#lsp_linter#HandleLSPDiagnostics(a:conn_id, l:uri, l:diagnostics)
|
||||
elseif has_key(s:diagnostic_uri_map, get(a:response, 'id'))
|
||||
let l:uri = remove(s:diagnostic_uri_map, a:response.id)
|
||||
let l:diagnostics = a:response.result.kind is# 'unchanged'
|
||||
\ ? 'unchanged'
|
||||
\ : a:response.result.items
|
||||
|
||||
call s:HandleLSPDiagnostics(a:conn_id, l:uri, l:diagnostics)
|
||||
call ale#lsp_linter#HandleLSPDiagnostics(a:conn_id, l:uri, l:diagnostics)
|
||||
elseif l:method is# 'window/showMessage'
|
||||
call ale#lsp_window#HandleShowMessage(
|
||||
\ s:lsp_linter_map[a:conn_id].name,
|
||||
|
||||
@@ -38,13 +38,36 @@ module.start = function(config)
|
||||
-- functions so all of the functionality in ALE works.
|
||||
["textDocument/publishDiagnostics"] = function(err, result, _, _)
|
||||
if err == nil then
|
||||
vim.fn["ale#lsp_linter#HandleLSPResponse"](config.name, {
|
||||
jsonrpc = "2.0",
|
||||
method = "textDocument/publishDiagnostics",
|
||||
params = result
|
||||
})
|
||||
vim.fn["ale#lsp_linter#HandleLSPDiagnostics"](
|
||||
config.name,
|
||||
result.uri,
|
||||
result.diagnostics
|
||||
)
|
||||
end
|
||||
end
|
||||
end,
|
||||
-- Handle pull model diagnostic data.
|
||||
["textDocument/diagnostic"] = function(err, result, request, _)
|
||||
if err == nil then
|
||||
local diagnostics
|
||||
|
||||
if result.kind == "unchanged" then
|
||||
diagnostics = "unchanged"
|
||||
else
|
||||
diagnostics = result.items
|
||||
end
|
||||
|
||||
vim.fn["ale#lsp_linter#HandleLSPDiagnostics"](
|
||||
config.name,
|
||||
request.params.textDocument.uri,
|
||||
diagnostics
|
||||
)
|
||||
end
|
||||
end,
|
||||
-- When the pull model is enabled we have to handle and return
|
||||
-- some kind of data for a server diagnostic refresh request.
|
||||
["workspace/diagnostic/refresh"] = function()
|
||||
return {}
|
||||
end,
|
||||
}
|
||||
|
||||
config.on_init = function(client, _)
|
||||
@@ -70,6 +93,16 @@ module.start = function(config)
|
||||
return vim.fn["ale#lsp#GetLanguage"](config.name, bufnr)
|
||||
end
|
||||
|
||||
local capabilities = vim.lsp.protocol.make_client_capabilities()
|
||||
|
||||
-- Language servers like Pyright do not enable the diagnostics pull model
|
||||
-- unless dynamicRegistration is enabled for diagnostics.
|
||||
if capabilities.textDocument.diagnostic ~= nil then
|
||||
capabilities.textDocument.diagnostic.dynamicRegistration = true
|
||||
config.capabilities = capabilities
|
||||
end
|
||||
|
||||
---@diagnostic disable-next-line: missing-fields
|
||||
return vim.lsp.start(config, {
|
||||
attach = false,
|
||||
silent = true,
|
||||
@@ -93,6 +126,10 @@ end
|
||||
module.send_message = function(args)
|
||||
local client = vim.lsp.get_client_by_id(args.client_id)
|
||||
|
||||
if client == nil then
|
||||
return 0
|
||||
end
|
||||
|
||||
if args.is_notification then
|
||||
-- For notifications we send a request and expect no direct response.
|
||||
local success = client.notify(args.method, args.params)
|
||||
|
||||
@@ -6,6 +6,7 @@ describe("ale.lsp.start", function()
|
||||
local rpc_connect_calls
|
||||
local vim_fn_calls
|
||||
local defer_calls
|
||||
local nvim_default_capabilities
|
||||
|
||||
setup(function()
|
||||
_G.vim = {
|
||||
@@ -21,7 +22,7 @@ describe("ale.lsp.start", function()
|
||||
return "python"
|
||||
end
|
||||
|
||||
if key ~= "ale#lsp_linter#HandleLSPResponse"
|
||||
if key ~= "ale#lsp_linter#HandleLSPDiagnostics"
|
||||
and key ~= "ale#lsp#UpdateCapabilities"
|
||||
and key ~= "ale#lsp#CallInitCallbacks"
|
||||
then
|
||||
@@ -49,6 +50,11 @@ describe("ale.lsp.start", function()
|
||||
|
||||
return 42
|
||||
end,
|
||||
protocol = {
|
||||
make_client_capabilities = function()
|
||||
return nvim_default_capabilities
|
||||
end,
|
||||
},
|
||||
},
|
||||
}
|
||||
end)
|
||||
@@ -62,6 +68,9 @@ describe("ale.lsp.start", function()
|
||||
rpc_connect_calls = {}
|
||||
vim_fn_calls = {}
|
||||
defer_calls = {}
|
||||
nvim_default_capabilities = {
|
||||
textDocument = {},
|
||||
}
|
||||
end)
|
||||
|
||||
it("should start lsp programs with the correct arguments", function()
|
||||
@@ -148,6 +157,24 @@ describe("ale.lsp.start", function()
|
||||
eq({{"ale#lsp#GetLanguage", "server:/code", 347}}, vim_fn_calls)
|
||||
end)
|
||||
|
||||
it("should enable dynamicRegistration for the pull model", function()
|
||||
nvim_default_capabilities = {textDocument = {diagnostic = {}}}
|
||||
|
||||
lsp.start({name = "server:/code"})
|
||||
eq(1, #start_calls)
|
||||
|
||||
eq(
|
||||
{
|
||||
textDocument = {
|
||||
diagnostic = {
|
||||
dynamicRegistration = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
start_calls[1][1].capabilities
|
||||
)
|
||||
end)
|
||||
|
||||
it("should initialize clients with ALE correctly", function()
|
||||
lsp.start({name = "server:/code"})
|
||||
|
||||
@@ -185,39 +212,150 @@ describe("ale.lsp.start", function()
|
||||
handler_names[key] = true
|
||||
end
|
||||
|
||||
eq({["textDocument/publishDiagnostics"] = true}, handler_names)
|
||||
eq({
|
||||
["textDocument/publishDiagnostics"] = true,
|
||||
["textDocument/diagnostic"] = true,
|
||||
["workspace/diagnostic/refresh"] = true,
|
||||
}, handler_names)
|
||||
end)
|
||||
|
||||
it("should handle push model published diagnostics", function()
|
||||
lsp.start({name = "server:/code"})
|
||||
|
||||
eq(1, #start_calls)
|
||||
|
||||
local handlers = start_calls[1][1].handlers
|
||||
|
||||
eq("function", type(handlers["textDocument/publishDiagnostics"]))
|
||||
|
||||
handlers["textDocument/publishDiagnostics"](nil, {
|
||||
{
|
||||
lnum = 1,
|
||||
end_lnum = 2,
|
||||
col = 3,
|
||||
end_col = 5,
|
||||
severity = 1,
|
||||
code = "123",
|
||||
message = "Warning message",
|
||||
uri = "file://code/foo.py",
|
||||
diagnostics = {
|
||||
{
|
||||
lnum = 1,
|
||||
end_lnum = 2,
|
||||
col = 3,
|
||||
end_col = 5,
|
||||
severity = 1,
|
||||
code = "123",
|
||||
message = "Warning message",
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
eq({
|
||||
{
|
||||
"ale#lsp_linter#HandleLSPResponse",
|
||||
"ale#lsp_linter#HandleLSPDiagnostics",
|
||||
"server:/code",
|
||||
"file://code/foo.py",
|
||||
{
|
||||
jsonrpc = "2.0",
|
||||
method = "textDocument/publishDiagnostics",
|
||||
params = {
|
||||
{
|
||||
lnum = 1,
|
||||
end_lnum = 2,
|
||||
col = 3,
|
||||
end_col = 5,
|
||||
severity = 1,
|
||||
code = "123",
|
||||
message = "Warning message",
|
||||
},
|
||||
{
|
||||
lnum = 1,
|
||||
end_lnum = 2,
|
||||
col = 3,
|
||||
end_col = 5,
|
||||
severity = 1,
|
||||
code = "123",
|
||||
message = "Warning message",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, vim_fn_calls)
|
||||
end)
|
||||
|
||||
it("should respond to workspace diagnostic refresh requests", function()
|
||||
lsp.start({name = "server:/code"})
|
||||
|
||||
eq(1, #start_calls)
|
||||
|
||||
local handlers = start_calls[1][1].handlers
|
||||
|
||||
eq("function", type(handlers["workspace/diagnostic/refresh"]))
|
||||
|
||||
eq({}, handlers["workspace/diagnostic/refresh"]())
|
||||
end)
|
||||
|
||||
it("should handle pull model diagnostics", function()
|
||||
lsp.start({name = "server:/code"})
|
||||
|
||||
eq(1, #start_calls)
|
||||
|
||||
local handlers = start_calls[1][1].handlers
|
||||
|
||||
eq("function", type(handlers["textDocument/diagnostic"]))
|
||||
|
||||
handlers["textDocument/diagnostic"](
|
||||
nil,
|
||||
{
|
||||
kind = "full",
|
||||
items = {
|
||||
{
|
||||
lnum = 1,
|
||||
end_lnum = 2,
|
||||
col = 3,
|
||||
end_col = 5,
|
||||
severity = 1,
|
||||
code = "123",
|
||||
message = "Warning message",
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
params = {
|
||||
textDocument = {
|
||||
uri = "file://code/foo.py",
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
eq({
|
||||
{
|
||||
"ale#lsp_linter#HandleLSPDiagnostics",
|
||||
"server:/code",
|
||||
"file://code/foo.py",
|
||||
{
|
||||
{
|
||||
lnum = 1,
|
||||
end_lnum = 2,
|
||||
col = 3,
|
||||
end_col = 5,
|
||||
severity = 1,
|
||||
code = "123",
|
||||
message = "Warning message",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, vim_fn_calls)
|
||||
end)
|
||||
|
||||
it("should handle unchanged pull model diagnostics", function()
|
||||
lsp.start({name = "server:/code"})
|
||||
|
||||
eq(1, #start_calls)
|
||||
|
||||
local handlers = start_calls[1][1].handlers
|
||||
|
||||
eq("function", type(handlers["textDocument/diagnostic"]))
|
||||
|
||||
handlers["textDocument/diagnostic"](
|
||||
nil,
|
||||
{kind = "unchanged"},
|
||||
{
|
||||
params = {
|
||||
textDocument = {
|
||||
uri = "file://code/foo.py",
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
eq({
|
||||
{
|
||||
"ale#lsp_linter#HandleLSPDiagnostics",
|
||||
"server:/code",
|
||||
"file://code/foo.py",
|
||||
"unchanged",
|
||||
},
|
||||
}, vim_fn_calls)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user